Fix up blockstate rebuild. Closes #2221. Also fix formatting. IDEA has differences. Solved now.

This commit is contained in:
cpw 2015-11-28 16:30:58 -05:00
parent 02e9b9d99c
commit 21173c3b65
5 changed files with 780 additions and 476 deletions

View File

@ -9,28 +9,25 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import com.google.common.base.Throwables;
import com.google.common.collect.*;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.Validate;
import org.apache.logging.log4j.Level;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBanner;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.ObjectIntIdentityMap;
import net.minecraft.util.RegistryNamespaced;
import net.minecraft.util.RegistryNamespacedDefaultedByKey;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.functions.GenericIterableFactory;
import net.minecraftforge.fml.common.registry.RegistryDelegate.Delegate;
import com.google.common.base.Function;
public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaultedByKey<ResourceLocation,I> {
public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaultedByKey<ResourceLocation, I>
{
public static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("fml.debugRegistryEntries", "false"));
private final Class<I> superType;
private final boolean isDelegated;
@ -43,7 +40,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
* Aliases are resource location to resource location pointers, allowing for alternative names to be supplied
* pointing at the same thing. They are used to allow programmatic migration of an ID.
*/
private final Map <ResourceLocation, ResourceLocation> aliases = Maps.newHashMap();
private final Map<ResourceLocation, ResourceLocation> aliases = Maps.newHashMap();
/**
* Persistent substitutions are the mechanism to allow mods to override specific behaviours with new behaviours.
*/
@ -58,7 +55,20 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
private final Set<Integer> blockedIds = Sets.newHashSet();
private final BitSet availabilityMap;
private final AddCallback<I> addCallback;
public interface AddCallback<T>
{
public void onAdd(T obj, int id);
}
FMLControlledNamespacedRegistry(ResourceLocation defaultKey, int maxIdValue, int minIdValue, Class<I> type, boolean isDelegated)
{
this(defaultKey, maxIdValue, minIdValue, type, isDelegated, null);
}
FMLControlledNamespacedRegistry(ResourceLocation defaultKey, int maxIdValue, int minIdValue, Class<I> type, boolean isDelegated, AddCallback<I> callback)
{
super(defaultKey);
this.superType = type;
@ -67,16 +77,22 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
this.minId = minIdValue;
this.availabilityMap = new BitSet(maxIdValue + 1);
this.isDelegated = isDelegated;
if (this.isDelegated) {
try {
if (this.isDelegated)
{
try
{
this.delegateAccessor = type.getField("delegate");
} catch (NoSuchFieldException e) {
} catch (NoSuchFieldException e)
{
FMLLog.log(Level.ERROR, e, "Delegate class identified with missing delegate field");
throw Throwables.propagate(e);
}
} else {
}
else
{
this.delegateAccessor = null;
}
this.addCallback = callback;
}
void validateContent(ResourceLocation registryName)
@ -88,21 +104,45 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
boolean isSubstituted = activeSubstitutions.containsKey(name);
// name lookup failed -> obj is not in the obj<->name map
if (name == null) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, doesn't yield a name.", registryName, obj, id));
if (name == null)
{
throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, doesn't yield a name.", registryName, obj, id));
}
// id lookup failed -> obj is not in the obj<->id map
if (!isSubstituted && id < 0) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s, doesn't yield an id.", registryName, obj, name));
if (!isSubstituted && id < 0)
{
throw new IllegalStateException(String.format("Registry entry for %s %s, name %s, doesn't yield an id.", registryName, obj, name));
}
// id is too high
if (id > maxId) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s uses the too large id %d.", registryName, obj, name, id));
if (id > maxId)
{
throw new IllegalStateException(String.format("Registry entry for %s %s, name %s uses the too large id %d.", registryName, obj, name, id));
}
// the rest of the tests don't really work for substituted items or blocks
if (isSubstituted) continue;
if (isSubstituted)
{
continue;
}
// 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, registryName, obj));
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, registryName, 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, registryName, obj));
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, registryName, 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 (getId(name) != id)
{
throw new IllegalStateException(String.format("Registry entry for name %s doesn't yield the expected id %d.", name, id));
}
// entry is blocked, thus should be empty
if (blockedIds.contains(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as dangling.", registryName, obj, id, name));
if (blockedIds.contains(id))
{
throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as dangling.", registryName, obj, id, name));
}
}
}
@ -110,7 +150,10 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
@SuppressWarnings("unchecked")
void set(FMLControlledNamespacedRegistry<I> otherRegistry)
{
if (this.superType != otherRegistry.superType) throw new IllegalArgumentException("incompatible registry");
if (this.superType != otherRegistry.superType)
{
throw new IllegalArgumentException("incompatible registry");
}
this.optionalDefaultKey = otherRegistry.optionalDefaultKey;
this.maxId = otherRegistry.maxId;
@ -155,8 +198,14 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
public void putObject(ResourceLocation name, I thing)
{
if (name == null) throw new NullPointerException("Can't use a null-name for the registry.");
if (thing == null) throw new NullPointerException("Can't add null-object to the registry.");
if (name == null)
{
throw new NullPointerException("Can't use a null-name for the registry.");
}
if (thing == null)
{
throw new NullPointerException("Can't add null-object to the registry.");
}
ResourceLocation existingName = getNameForObject(thing);
@ -177,7 +226,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
/**
* Fetch the object identified by the specified name or the default object.
*
* <p/>
* For blocks the default object is the air block, for items it's null.
*
* @param name Unique name identifying the object.
@ -192,7 +241,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
/**
* Fetch the object identified by the specified id or the default object.
*
* <p/>
* For blocks the default object is the air block, for items it's null.
*
* @param id ID identifying the object.
@ -207,9 +256,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
/**
* Get the id for the specified object.
*
* <p/>
* Don't hold onto the id across the world, it's being dynamically re-mapped as needed.
*
* <p/>
* Usually the name should be used instead of the id, if using the Block/Item object itself is
* not suitable for the task.
*
@ -246,7 +295,10 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
{
name = aliases.get(name);
if (name != null) return getRaw(name);
if (name != null)
{
return getRaw(name);
}
}
return ret;
@ -254,7 +306,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
/**
* Determine if the registry has an entry for the specified name.
*
* <p/>
* Aliased names will be resolved as well.
*
* @param name Object name to check.
@ -269,7 +321,10 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
{
name = aliases.get(name);
if (name != null) return containsKey(name);
if (name != null)
{
return containsKey(name);
}
}
return ret;
@ -277,9 +332,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
/**
* Get the id for the specified object.
*
* <p/>
* Don't hold onto the id across the world, it's being dynamically re-mapped as needed.
*
* <p/>
* Usually the name should be used instead of the id, if using the Block/Item object itself is
* not suitable for the task.
*
@ -289,7 +344,10 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
public int getId(ResourceLocation itemName)
{
I obj = getRaw(itemName);
if (obj == null) return -1;
if (obj == null)
{
return -1;
}
return getId(obj);
}
@ -312,6 +370,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
idMapping.put(getNameForObject(thing), getId(thing));
}
}
public void serializeAliases(Map<ResourceLocation, ResourceLocation> map)
{
map.putAll(this.aliases);
@ -325,15 +384,21 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
/**
* 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 id ID to use if available, auto-assigned otherwise.
* @param name Name to use, prefixed by the mod id.
* @param thing Object to add.
* @return ID eventually allocated.
*/
int add(int id, ResourceLocation name, I thing)
{
if (name == null) throw new NullPointerException(String.format("Can't use a null-name for the registry, object %s.", thing));
if (thing == null) throw new NullPointerException(String.format("Can't add null-object to the registry, name %s.", name));
if (name == null)
{
throw new NullPointerException(String.format("Can't use a null-name for the registry, object %s.", thing));
}
if (thing == null)
{
throw new NullPointerException(String.format("Can't add null-object to the registry, name %s.", name));
}
if (optionalDefaultKey != null && optionalDefaultKey.equals(name) && this.optionalDefaultObject == null)
{
this.optionalDefaultObject = thing;
@ -376,7 +441,10 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
{
I oldThing = thing;
thing = activeSubstitutions.get(name);
if (DEBUG) FMLLog.getLogger().log(Level.DEBUG, "Active substitution: {} {}@{} -> {}@{}",name, oldThing.getClass().getName(), System.identityHashCode(oldThing), thing.getClass().getName(), System.identityHashCode(thing));
if (DEBUG)
{
FMLLog.getLogger().log(Level.DEBUG, "Active substitution: {} {}@{} -> {}@{}", name, oldThing.getClass().getName(), System.identityHashCode(oldThing), thing.getClass().getName(), System.identityHashCode(thing));
}
}
@ -386,7 +454,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
getExistingDelegate(thing).setResourceName(name);
}
if (DEBUG)
{
FMLLog.finer("Registry add: %s %d %s (req. id %d)", name, idToUse, thing, id);
}
return idToUse;
}
@ -394,12 +464,14 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
{
aliases.put(from, to);
if (DEBUG)
{
FMLLog.finer("Registry alias: %s -> %s", from, to);
}
}
Map<ResourceLocation,Integer> getEntriesNotIn(FMLControlledNamespacedRegistry<I> registry)
Map<ResourceLocation, Integer> getEntriesNotIn(FMLControlledNamespacedRegistry<I> registry)
{
Map<ResourceLocation,Integer> ret = new HashMap<ResourceLocation, Integer>();
Map<ResourceLocation, Integer> ret = new HashMap<ResourceLocation, Integer>();
for (I thing : this.typeSafeIterable())
{
@ -418,7 +490,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
void dump(ResourceLocation registryName)
{
if (!DEBUG)
{
return;
}
List<Integer> ids = new ArrayList<Integer>();
@ -442,13 +516,26 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
*/
private void addObjectRaw(int id, ResourceLocation name, I thing)
{
if (name == null) throw new NullPointerException("The name to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug?");
if (thing == null) throw new NullPointerException("The object to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug?");
if (!superType.isInstance(thing)) throw new IllegalArgumentException("The object to be added to the registry is not of the right type. Reflection/ASM hackery? Registry bug?");
if (name == null)
{
throw new NullPointerException("The name to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug?");
}
if (thing == null)
{
throw new NullPointerException("The object to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug?");
}
if (!superType.isInstance(thing))
{
throw new IllegalArgumentException("The object to be added to the registry is not of the right type. Reflection/ASM hackery? Registry bug?");
}
underlyingIntegerMap.put(thing, id); // obj <-> id
super.putObject(name, thing); // name <-> obj
availabilityMap.set(id);
if (addCallback != null)
{
addCallback.onAdd(thing, id);
}
}
public I getDefaultValue()
@ -456,19 +543,24 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
return optionalDefaultObject;
}
public RegistryDelegate<I> getDelegate(I thing, Class<I> clazz) {
public RegistryDelegate<I> getDelegate(I thing, Class<I> clazz)
{
return new RegistryDelegate.Delegate<I>(thing, clazz);
}
@SuppressWarnings("unchecked")
public Delegate<I> getExistingDelegate(I thing) {
try {
return (Delegate<I>) delegateAccessor.get(thing);
} catch (IllegalAccessException e) {
public Delegate<I> getExistingDelegate(I thing)
{
try
{
return (Delegate<I>)delegateAccessor.get(thing);
} catch (IllegalAccessException e)
{
FMLLog.log(Level.ERROR, e, "Illegal attempt to access delegate");
throw Throwables.propagate(e);
}
}
void activateSubstitution(ResourceLocation nameToReplace)
{
if (getPersistentSubstitutions().containsKey(nameToReplace))
@ -480,7 +572,8 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
}
}
void addSubstitutionAlias(String modId, ResourceLocation nameToReplace, I replacement) throws ExistingSubstitutionException {
void addSubstitutionAlias(String modId, ResourceLocation nameToReplace, I replacement) throws ExistingSubstitutionException
{
if (getPersistentSubstitutions().containsKey(nameToReplace) || getPersistentSubstitutions().containsValue(replacement))
{
FMLLog.severe("The substitution of %s has already occurred. You cannot duplicate substitutions", nameToReplace);
@ -515,8 +608,11 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
public void validateKey()
{
if (this.optionalDefaultKey != null)
{
Validate.notNull(this.optionalDefaultObject);
}
}
/*
* This iterator is used by some regular MC methods to visit all blocks, we need to include substitutions
* Compare #typeSafeIterable()
@ -525,19 +621,23 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
@Override
public Iterator<I> iterator()
{
return Iterators.concat(super.iterator(),getPersistentSubstitutions().values().iterator());
return Iterators.concat(super.iterator(), getPersistentSubstitutions().values().iterator());
}
FMLControlledNamespacedRegistry<I> makeShallowCopy() {
FMLControlledNamespacedRegistry<I> makeShallowCopy()
{
return new FMLControlledNamespacedRegistry<I>(optionalDefaultKey, maxId, minId, superType, isDelegated);
}
void resetSubstitutionDelegates()
{
if (!isDelegated) return;
for (I obj: typeSafeIterable()) {
if (!isDelegated)
{
return;
}
for (I obj : typeSafeIterable())
{
Delegate<I> delegate = getExistingDelegate(obj);
delegate.changeReference(obj);
}
@ -546,49 +646,62 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
@SuppressWarnings("unchecked")
public <T> FMLControlledNamespacedRegistry<T> asType(Class<? extends T> type)
{
return (FMLControlledNamespacedRegistry<T>) this;
return (FMLControlledNamespacedRegistry<T>)this;
}
public void serializeBlockList(Set<Integer> blocked) {
public void serializeBlockList(Set<Integer> blocked)
{
blocked.addAll(this.blockedIds);
}
public Set<? extends ResourceLocation> getActiveSubstitutions() {
public Set<? extends ResourceLocation> getActiveSubstitutions()
{
return activeSubstitutions.keySet();
}
public void loadAliases(Map<ResourceLocation, ResourceLocation> aliases) {
for (Map.Entry<ResourceLocation, ResourceLocation> alias : aliases.entrySet()) {
public void loadAliases(Map<ResourceLocation, ResourceLocation> aliases)
{
for (Map.Entry<ResourceLocation, ResourceLocation> alias : aliases.entrySet())
{
addAlias(alias.getKey(), alias.getValue());
}
}
public void loadSubstitutions(Set<ResourceLocation> substitutions) {
for (ResourceLocation rl : substitutions) {
public void loadSubstitutions(Set<ResourceLocation> substitutions)
{
for (ResourceLocation rl : substitutions)
{
activateSubstitution(rl);
}
}
public void loadBlocked(Set<Integer> blocked) {
for (Integer id : blocked) {
public void loadBlocked(Set<Integer> blocked)
{
for (Integer id : blocked)
{
blockedIds.add(id);
availabilityMap.set(id);
}
}
public void loadIds(Map<ResourceLocation, Integer> ids, Map<ResourceLocation, Integer> missingIds, Map<ResourceLocation, Integer[]> remappedIds, FMLControlledNamespacedRegistry<I> currentRegistry, ResourceLocation registryName) {
for (Map.Entry<ResourceLocation, Integer> entry : ids.entrySet()) {
public void loadIds(Map<ResourceLocation, Integer> ids, Map<ResourceLocation, Integer> missingIds, Map<ResourceLocation, Integer[]> remappedIds, FMLControlledNamespacedRegistry<I> currentRegistry, ResourceLocation registryName)
{
for (Map.Entry<ResourceLocation, Integer> entry : ids.entrySet())
{
ResourceLocation itemName = entry.getKey();
int newId = entry.getValue();
int currId = currentRegistry.getId(itemName);
if (currId == -1) {
if (currId == -1)
{
FMLLog.info("Found a missing id from the world %s", itemName);
missingIds.put(entry.getKey(), newId);
continue; // no block/item -> nothing to add
} else if (currId != newId) {
}
else if (currId != newId)
{
FMLLog.fine("Fixed %s id mismatch %s: %d (init) -> %d (map).", registryName, itemName, currId, newId);
remappedIds.put(itemName, new Integer[]{currId, newId});
remappedIds.put(itemName, new Integer[] {currId, newId});
}
I obj = currentRegistry.getRaw(itemName);
@ -596,7 +709,8 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
}
}
public void blockId(int id) {
public void blockId(int id)
{
blockedIds.add(id);
}
}

View File

@ -14,6 +14,8 @@ package net.minecraftforge.fml.common.registry;
import java.util.Map;
import com.google.common.collect.Maps;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
@ -22,12 +24,9 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.registry.GameRegistry.Type;
import net.minecraftforge.fml.common.registry.GameRegistry.UniqueIdentifier;
import com.google.common.collect.Maps;
public class GameData {
public class GameData
{
static final int MIN_BLOCK_ID = 0;
static final int MAX_BLOCK_ID = 4095;
static final int MIN_ITEM_ID = 4096;
@ -41,7 +40,8 @@ public class GameData {
*
* @return Block Registry.
*/
public static FMLControlledNamespacedRegistry<Block> getBlockRegistry() {
public static FMLControlledNamespacedRegistry<Block> getBlockRegistry()
{
return getMain().iBlockRegistry;
}
@ -50,7 +50,8 @@ public class GameData {
*
* @return Item Registry.
*/
public static FMLControlledNamespacedRegistry<Item> getItemRegistry() {
public static FMLControlledNamespacedRegistry<Item> getItemRegistry()
{
return getMain().iItemRegistry;
}
@ -59,45 +60,59 @@ public class GameData {
***************************************************/
static Item findItem(String modId, String name) {
static Item findItem(String modId, String name)
{
return getMain().iItemRegistry.getObject(new ResourceLocation(modId, name));
}
static Block findBlock(String modId, String name) {
static Block findBlock(String modId, String name)
{
return getMain().iBlockRegistry.getObject(new ResourceLocation(modId, name));
}
static UniqueIdentifier getUniqueName(Block block) {
if (block == null) return null;
static GameRegistry.UniqueIdentifier getUniqueName(Block block)
{
if (block == null)
{
return null;
}
Object name = getMain().iBlockRegistry.getNameForObject(block);
return new UniqueIdentifier(name);
return new GameRegistry.UniqueIdentifier(name);
}
static UniqueIdentifier getUniqueName(Item item) {
if (item == null) return null;
static GameRegistry.UniqueIdentifier getUniqueName(Item item)
{
if (item == null)
{
return null;
}
Object name = getMain().iItemRegistry.getNameForObject(item);
return new UniqueIdentifier(name);
return new GameRegistry.UniqueIdentifier(name);
}
protected static GameData getMain() {
protected static GameData getMain()
{
return mainData;
}
// internal registry objects
private final FMLControlledNamespacedRegistry<Block> iBlockRegistry = PersistentRegistryManager.createRegistry(PersistentRegistryManager.BLOCKS, Block.class, new ResourceLocation("minecraft:air"), MAX_BLOCK_ID, MIN_BLOCK_ID, true);
private final FMLControlledNamespacedRegistry<Block> iBlockRegistry = PersistentRegistryManager.createRegistry(PersistentRegistryManager.BLOCKS, Block.class, new ResourceLocation("minecraft:air"), MAX_BLOCK_ID, MIN_BLOCK_ID, true, BlockStateCapture.INSTANCE);
private final FMLControlledNamespacedRegistry<Item> iItemRegistry = PersistentRegistryManager.createRegistry(PersistentRegistryManager.ITEMS, Item.class, null, MAX_ITEM_ID, MIN_ITEM_ID, true);
int registerItem(Item item, String name) // from GameRegistry
{
int index = name.indexOf(':');
if (index != -1)
{
FMLLog.bigWarning("Dangerous extra prefix %s for name %s, invalid registry invocation/invalid name?", name.substring(0, index), name);
}
ResourceLocation rl = addPrefix(name);
return registerItem(item, rl, -1);
}
private int registerItem(Item item, ResourceLocation name, int idHint) {
private int registerItem(Item item, ResourceLocation name, int idHint)
{
return iItemRegistry.add(idHint, name, item);
}
@ -105,20 +120,17 @@ public class GameData {
{
int index = name.indexOf(':');
if (index != -1)
{
FMLLog.bigWarning("Dangerous alternative prefix %s for name %s, invalid registry invocation/invalid name?", name.substring(0, index), name);
}
ResourceLocation rl = addPrefix(name);
return registerBlock(block, rl, -1);
}
private int registerBlock(Block block, ResourceLocation name, int idHint) {
int blockId = iBlockRegistry.add(idHint, name, block);
for (IBlockState state : block.getBlockState().getValidStates()) {
GameData.BLOCKSTATE_TO_ID.put(state, blockId << 4 | block.getMetaFromState(state));
}
return blockId;
private int registerBlock(Block block, ResourceLocation name, int idHint)
{
return iBlockRegistry.add(idHint, name, block);
}
/**
@ -133,33 +145,41 @@ public class GameData {
* @param name name to prefix.
* @return prefixed name.
*/
private ResourceLocation addPrefix(String name) {
private ResourceLocation addPrefix(String name)
{
int index = name.lastIndexOf(':');
String oldPrefix = index == -1 ? "" : name.substring(0, index);
String prefix;
ModContainer mc = Loader.instance().activeModContainer();
if (mc != null) {
if (mc != null)
{
prefix = mc.getModId();
} else // no mod container, assume minecraft
}
else // no mod container, assume minecraft
{
prefix = "minecraft";
}
if (!oldPrefix.equals(prefix) && oldPrefix.length() > 0) {
if (!oldPrefix.equals(prefix) && oldPrefix.length() > 0)
{
prefix = oldPrefix;
}
return new ResourceLocation(prefix,name);
return new ResourceLocation(prefix, name);
}
void registerSubstitutionAlias(String name, Type type, Object toReplace) throws ExistingSubstitutionException {
void registerSubstitutionAlias(String name, GameRegistry.Type type, Object toReplace) throws ExistingSubstitutionException
{
ResourceLocation nameToSubstitute = new ResourceLocation(Loader.instance().activeModContainer().getModId(), name);
if (type == Type.BLOCK) {
iBlockRegistry.addSubstitutionAlias(Loader.instance().activeModContainer().getModId(), nameToSubstitute, (Block) toReplace);
if (type == GameRegistry.Type.BLOCK)
{
iBlockRegistry.addSubstitutionAlias(Loader.instance().activeModContainer().getModId(), nameToSubstitute, (Block)toReplace);
iBlockRegistry.activateSubstitution(nameToSubstitute);
} else if (type == Type.ITEM) {
iItemRegistry.addSubstitutionAlias(Loader.instance().activeModContainer().getModId(), nameToSubstitute, (Item) toReplace);
}
else if (type == GameRegistry.Type.ITEM)
{
iItemRegistry.addSubstitutionAlias(Loader.instance().activeModContainer().getModId(), nameToSubstitute, (Item)toReplace);
iItemRegistry.activateSubstitution(nameToSubstitute);
}
}
@ -167,26 +187,45 @@ public class GameData {
private static Map<Block, Item> BLOCK_TO_ITEM = Maps.newHashMap();
//Internal: DO NOT USE, will change without warning.
public static Map getBlockItemMap() {
public static Map getBlockItemMap()
{
return BLOCK_TO_ITEM;
}
private static ClearableObjectIntIdentityMap<IBlockState> BLOCKSTATE_TO_ID = new ClearableObjectIntIdentityMap<IBlockState>();
//Internal: DO NOT USE, will change without warning.
public static ObjectIntIdentityMap getBlockStateIDMap() {
public static ClearableObjectIntIdentityMap<IBlockState> getBlockStateIDMap()
{
return BLOCKSTATE_TO_ID;
}
//Lets us clear the map so we can rebuild it.
private static class ClearableObjectIntIdentityMap<I> extends ObjectIntIdentityMap<I> {
private void clear() {
static class ClearableObjectIntIdentityMap<I> extends ObjectIntIdentityMap<I>
{
void clear()
{
this.identityMap.clear();
this.objectList.clear();
}
}
public <T> RegistryDelegate<T> makeDelegate(T obj, Class<T> rootClass) {
public <T> RegistryDelegate<T> makeDelegate(T obj, Class<T> rootClass)
{
return PersistentRegistryManager.makeDelegate(obj, rootClass);
}
private static class BlockStateCapture implements FMLControlledNamespacedRegistry.AddCallback<Block>
{
static final BlockStateCapture INSTANCE = new BlockStateCapture();
@Override
public void onAdd(Block block, int blockId)
{
for (IBlockState state : block.getBlockState().getValidStates())
{
GameData.BLOCKSTATE_TO_ID.put(state, blockId << 4 | block.getMetaFromState(state));
}
}
}
}

View File

@ -25,6 +25,17 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import org.apache.logging.log4j.Level;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
@ -48,18 +59,6 @@ import net.minecraftforge.fml.common.LoaderException;
import net.minecraftforge.fml.common.LoaderState;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import org.apache.logging.log4j.Level;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
public class GameRegistry
{
private static Set<IWorldGenerator> worldGenerators = Sets.newHashSet();
@ -70,9 +69,9 @@ public class GameRegistry
/**
* Register a world generator - something that inserts new block types into the world
*
* @param generator the generator
* @param generator the generator
* @param modGenerationWeight a weight to assign to this generator. Heavy weights tend to sink to the bottom of
* list of world generators (i.e. they run later)
* list of world generators (i.e. they run later)
*/
public static void registerWorldGenerator(IWorldGenerator generator, int modGenerationWeight)
{
@ -88,11 +87,11 @@ public class GameRegistry
* Callback hook for world gen - if your mod wishes to add extra mod related generation to the world
* call this
*
* @param chunkX Chunk X coordinate
* @param chunkZ Chunk Z coordinate
* @param world World we're generating into
* @param chunkX Chunk X coordinate
* @param chunkZ Chunk Z coordinate
* @param world World we're generating into
* @param chunkGenerator The chunk generator
* @param chunkProvider The chunk provider
* @param chunkProvider The chunk provider
*/
public static void generateWorld(int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
{
@ -116,7 +115,8 @@ public class GameRegistry
private static void computeSortedGeneratorList()
{
ArrayList<IWorldGenerator> list = Lists.newArrayList(worldGenerators);
Collections.sort(list, new Comparator<IWorldGenerator>() {
Collections.sort(list, new Comparator<IWorldGenerator>()
{
@Override
public int compare(IWorldGenerator o1, IWorldGenerator o2)
{
@ -139,8 +139,9 @@ public class GameRegistry
/**
* Register the specified Item with a mod specific name : overrides the standard type based name
* @param item The item to register
* @param name The mod-unique name to register it as - null will remove a custom name
*
* @param item The item to register
* @param name The mod-unique name to register it as - null will remove a custom name
* @param modId deprecated, unused
*/
public static Item registerItem(Item item, String name, String modId)
@ -156,9 +157,9 @@ public class GameRegistry
* referenced.
*
* @param nameToSubstitute The name to link to (this is the NEW block or item)
* @param type The type (Block or Item)
* @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
* @param type The type (Block or Item)
* @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 addSubstitutionAlias(String nameToSubstitute, GameRegistry.Type type, Object object) throws ExistingSubstitutionException
@ -168,8 +169,9 @@ public class GameRegistry
/**
* Register a block with the specified mod specific name
*
* @param block The block to register
* @param name The mod-unique name to register it as, will get prefixed by your modid.
* @param name The mod-unique name to register it as, will get prefixed by your modid.
*/
public static Block registerBlock(Block block, String name)
{
@ -178,20 +180,22 @@ public class GameRegistry
/**
* Register a block with the world, with the specified item class and block name
* @param block The block to register
*
* @param block The block to register
* @param itemclass The item type to register with it : null registers a block without associated item.
* @param name The mod-unique name to register it as, will get prefixed by your modid.
* @param name The mod-unique name to register it as, will get prefixed by your modid.
*/
public static Block registerBlock(Block block, Class<? extends ItemBlock> itemclass, String name)
{
return registerBlock(block, itemclass, name, new Object[]{});
return registerBlock(block, itemclass, name, new Object[] {});
}
/**
* Register a block with the world, with the specified item class, block name and owning modId
* @param block The block to register
* @param itemclass The item type to register with it : null registers a block without associated item.
* @param name The mod-unique name to register it as, will get prefixed by your modid.
*
* @param block The block to register
* @param itemclass The item type to register with it : null registers a block without associated item.
* @param name The mod-unique name to register it as, will get prefixed by your modid.
* @param itemCtorArgs Arguments to pass (after the required {@code Block} parameter) to the ItemBlock constructor (optional).
*/
@SuppressWarnings("unchecked")
@ -211,7 +215,7 @@ public class GameRegistry
ctorArgClasses[0] = Block.class;
for (int idx = 1; idx < ctorArgClasses.length; idx++)
{
ctorArgClasses[idx] = itemCtorArgs[idx-1].getClass();
ctorArgClasses[idx] = itemCtorArgs[idx - 1].getClass();
}
Constructor<? extends ItemBlock> itemCtor = itemclass.getConstructor(ctorArgClasses);
i = itemCtor.newInstance(ObjectArrays.concat(block, itemCtorArgs));
@ -224,8 +228,7 @@ public class GameRegistry
GameData.getBlockItemMap().put(block, i);
}
return block;
}
catch (Exception e)
} catch (Exception e)
{
FMLLog.log(Level.ERROR, e, "Caught an exception during block registration");
throw new LoaderException(e);
@ -277,14 +280,14 @@ public class GameRegistry
* This method allows for you to "rename" the 'id' of the tile entity.
*
* @param tileEntityClass The tileEntity class to register
* @param id The primary ID, this will be the ID that the tileentity saves as
* @param alternatives A list of alternative IDs that will also map to this class. These will never save, but they will load
* @param id The primary ID, this will be the ID that the tileentity saves as
* @param alternatives A list of alternative IDs that will also map to this class. These will never save, but they will load
*/
public static void registerTileEntityWithAlternatives(Class<? extends TileEntity> tileEntityClass, String id, String... alternatives)
{
TileEntity.addMapping(tileEntityClass, id);
Map<String,Class<?>> teMappings = ObfuscationReflectionHelper.getPrivateValue(TileEntity.class, null, "field_" + "145855_i", "nameToClassMap");
for (String s: alternatives)
Map<String, Class<?>> teMappings = ObfuscationReflectionHelper.getPrivateValue(TileEntity.class, null, "field_" + "145855_i", "nameToClassMap");
for (String s : alternatives)
{
if (!teMappings.containsKey(s))
{
@ -297,6 +300,7 @@ public class GameRegistry
{
fuelHandlers.add(handler);
}
public static int getFuelValue(ItemStack itemStack)
{
int fuelValue = 0;
@ -309,8 +313,9 @@ public class GameRegistry
/**
* Look up a mod block in the global "named item list"
*
* @param modId The modid owning the block
* @param name The name of the block itself
* @param name The name of the block itself
* @return The block or null if not found
*/
public static Block findBlock(String modId, String name)
@ -320,8 +325,9 @@ public class GameRegistry
/**
* Look up a mod item in the global "named item list"
*
* @param modId The modid owning the item
* @param name The name of the item itself
* @param name The name of the item itself
* @return The item or null if not found
*/
public static Item findItem(String modId, String name)
@ -337,6 +343,7 @@ public class GameRegistry
{
public final String modId;
public final String name;
UniqueIdentifier(String modId, String name)
{
this.modId = modId;
@ -361,7 +368,7 @@ public class GameRegistry
else if (obj instanceof ResourceLocation)
{
this.modId = ((ResourceLocation)obj).getResourceDomain();
this.name = ((ResourceLocation)obj).getResourcePath();
this.name = ((ResourceLocation)obj).getResourcePath();
}
else
{
@ -372,9 +379,15 @@ public class GameRegistry
@Override
public boolean equals(Object obj)
{
if (obj == null) return false;
if (obj.getClass() != this.getClass()) return false;
final UniqueIdentifier other = (UniqueIdentifier) obj;
if (obj == null)
{
return false;
}
if (obj.getClass() != this.getClass())
{
return false;
}
final UniqueIdentifier other = (UniqueIdentifier)obj;
return Objects.equal(modId, other.modId) && Objects.equal(name, other.name);
}
@ -391,13 +404,15 @@ public class GameRegistry
}
}
public enum Type {
public enum Type
{
BLOCK,
ITEM;
}
/**
* Look up the mod identifier data for a block.
*
* <p/>
* Note: uniqueness and persistence is only guaranteed by mods using the game registry
* correctly.
*
@ -409,9 +424,10 @@ public class GameRegistry
{
return GameData.getUniqueName(block);
}
/**
* Look up the mod identifier data for an item.
*
* <p/>
* Note: uniqueness and persistence is only guaranteed by mods using the game registry
* correctly.
*
@ -425,15 +441,14 @@ public class GameRegistry
}
/**
* ObjectHolder can be used to automatically populate public static final fields with entries
* from the registry. These values can then be referred within mod code directly.
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
public @interface ObjectHolder {
public @interface ObjectHolder
{
/**
* If used on a class, this represents a modid only.
* If used on a field, it represents a name, which can be abbreviated or complete.
@ -449,7 +464,7 @@ public class GameRegistry
* {@link ItemStack} instances, referring a specific item, potentially configured with NBT.
* These values can then be used in things like recipes and other places where ItemStacks
* might be required.
*
* <p/>
* If the item is not found, the field will be populated with null.
*/
@Retention(RetentionPolicy.RUNTIME)
@ -458,12 +473,14 @@ public class GameRegistry
{
/**
* The registry name of the item being looked up.
*
* @return The registry name
*/
public String value();
/**
* The metadata or damage value for the itemstack, defaults to 0.
*
* @return the metadata value
*/
public int meta() default 0;
@ -478,26 +495,31 @@ public class GameRegistry
/**
* Makes an {@link ItemStack} based on the itemName reference, with supplied meta, stackSize and nbt, if possible
*
* <p/>
* Will return null if the item doesn't exist (because it's not from a loaded mod for example)
* Will throw a {@link RuntimeException} if the nbtString is invalid for use in an {@link ItemStack}
*
* @param itemName a registry name reference
* @param meta the meta
* @param itemName a registry name reference
* @param meta the meta
* @param stackSize the stack size
* @param nbtString an nbt stack as a string, will be processed by {@link JsonToNBT}
* @return a new itemstack
*/
public static ItemStack makeItemStack(String itemName, int meta, int stackSize, String nbtString)
{
if (itemName == null) throw new IllegalArgumentException("The itemName cannot be null");
if (itemName == null)
{
throw new IllegalArgumentException("The itemName cannot be null");
}
Item item = GameData.getItemRegistry().getObject(new ResourceLocation(itemName));
if (item == null) {
if (item == null)
{
FMLLog.getLogger().log(Level.TRACE, "Unable to find item with name {}", itemName);
return null;
}
ItemStack is = new ItemStack(item,1,meta);
if (!Strings.isNullOrEmpty(nbtString)) {
ItemStack is = new ItemStack(item, 1, meta);
if (!Strings.isNullOrEmpty(nbtString))
{
NBTBase nbttag = null;
try
{
@ -507,11 +529,14 @@ public class GameRegistry
FMLLog.getLogger().log(Level.WARN, "Encountered an exception parsing ItemStack NBT string {}", nbtString, e);
throw Throwables.propagate(e);
}
if (!(nbttag instanceof NBTTagCompound)) {
if (!(nbttag instanceof NBTTagCompound))
{
FMLLog.getLogger().log(Level.WARN, "Unexpected NBT string - multiple values {}", nbtString);
throw new RuntimeException("Invalid NBT JSON");
} else {
is.setTagCompound((NBTTagCompound) nbttag);
}
else
{
is.setTagCompound((NBTTagCompound)nbttag);
}
}
return is;

View File

@ -1,61 +1,82 @@
package net.minecraftforge.fml.common.registry;
import java.io.IOException;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.collect.*;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraftforge.fml.common.*;
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent;
import org.apache.logging.log4j.Level;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nullable;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.StartupQuery;
import net.minecraftforge.fml.common.ZipperUtil;
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent;
/**
* Persistent registry manager. Manages the registries loading from disk, and from network. Handles staging
* registry data before loading uniformly into the active registry, and keeps a frozen registry instance
* for reversion after connection.
*
* @author cpw
*/
public class PersistentRegistryManager
{
private enum PersistentRegistry {
private enum PersistentRegistry
{
ACTIVE, FROZEN, STAGING;
private final BiMap<ResourceLocation,FMLControlledNamespacedRegistry<?>> registries = HashBiMap.create();
private final BiMap<Class<?>,ResourceLocation> registrySuperTypes = HashBiMap.create();
private final BiMap<ResourceLocation, FMLControlledNamespacedRegistry<?>> registries = HashBiMap.create();
private final BiMap<Class<?>, ResourceLocation> registrySuperTypes = HashBiMap.create();
@SuppressWarnings("unchecked")
<T> FMLControlledNamespacedRegistry<T> getRegistry(ResourceLocation key, Class<T> regType)
{
return (FMLControlledNamespacedRegistry<T>) registries.get(key);
return (FMLControlledNamespacedRegistry<T>)registries.get(key);
}
<T> FMLControlledNamespacedRegistry<T> getOrShallowCopyRegistry(ResourceLocation key, Class<T> regType, FMLControlledNamespacedRegistry<T> other)
{
if (!registries.containsKey(key)) {
if (!registries.containsKey(key))
{
registries.put(key, other.makeShallowCopy());
registrySuperTypes.put(regType, key);
}
return getRegistry(key, regType);
}
private <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> type, ResourceLocation defaultObjectKey, int minId, int maxId, boolean isDelegated) {
private <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> registryType, ResourceLocation optionalDefaultKey, int minId, int maxId, boolean hasDelegates)
{
return this.createRegistry(registryName, registryType, optionalDefaultKey, minId, maxId, hasDelegates, null);
}
private <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> type, ResourceLocation defaultObjectKey, int minId, int maxId, boolean isDelegated, FMLControlledNamespacedRegistry.AddCallback<T> addCallback)
{
Set<Class<?>> parents = Sets.newHashSet();
findSuperTypes(type, parents);
SetView<Class<?>> overlappedTypes = Sets.intersection(parents, registrySuperTypes.keySet());
if (!overlappedTypes.isEmpty()) {
if (!overlappedTypes.isEmpty())
{
Class<?> foundType = overlappedTypes.iterator().next();
FMLLog.severe("Found existing registry of type %1s named %2s, you cannot create a new registry (%3s) with type %4s, as %4s has a parent of that type", foundType, registrySuperTypes.get(foundType), registryName, type);
throw new IllegalArgumentException("Duplicate registry parent type found - you can only have one registry for a particular super type");
}
FMLControlledNamespacedRegistry<T> fmlControlledNamespacedRegistry = new FMLControlledNamespacedRegistry<T>(defaultObjectKey, maxId, minId, type, isDelegated);
FMLControlledNamespacedRegistry<T> fmlControlledNamespacedRegistry = new FMLControlledNamespacedRegistry<T>(defaultObjectKey, maxId, minId, type, isDelegated, addCallback);
registries.put(registryName, fmlControlledNamespacedRegistry);
registrySuperTypes.put(type, registryName);
return getRegistry(registryName, type);
@ -63,31 +84,37 @@ public class PersistentRegistryManager
private void findSuperTypes(Class<?> type, Set<Class<?>> types)
{
if (type == null || type == Object.class) {
if (type == null || type == Object.class)
{
return;
}
types.add(type);
for (Class<?> interfac : type.getInterfaces()) {
for (Class<?> interfac : type.getInterfaces())
{
findSuperTypes(interfac, types);
}
findSuperTypes(type.getSuperclass(),types);
findSuperTypes(type.getSuperclass(), types);
}
void clean() {
void clean()
{
registries.clear();
registrySuperTypes.clear();
}
boolean isPopulated() {
boolean isPopulated()
{
return !registries.isEmpty();
}
boolean containsRegistry(FMLControlledNamespacedRegistry<?> registry) {
boolean containsRegistry(FMLControlledNamespacedRegistry<?> registry)
{
return registries.containsValue(registry);
}
public <T> FMLControlledNamespacedRegistry<T> getRegistry(Class<T> rootClass) {
public <T> FMLControlledNamespacedRegistry<T> getRegistry(Class<T> rootClass)
{
ResourceLocation rl = registrySuperTypes.get(rootClass);
return getRegistry(rl, rootClass);
}
@ -96,20 +123,29 @@ public class PersistentRegistryManager
public static final ResourceLocation BLOCKS = new ResourceLocation("minecraft:blocks");
public static final ResourceLocation ITEMS = new ResourceLocation("minecraft:items");
public static <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> registryType, ResourceLocation optionalDefaultKey, int maxId, int minId, boolean hasDelegates) {
return PersistentRegistry.ACTIVE.createRegistry(registryName,registryType,optionalDefaultKey,minId, maxId, hasDelegates);
public static <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> registryType, ResourceLocation optionalDefaultKey, int maxId, int minId, boolean hasDelegates, FMLControlledNamespacedRegistry.AddCallback<T> addCallback)
{
return PersistentRegistry.ACTIVE.createRegistry(registryName, registryType, optionalDefaultKey, minId, maxId, hasDelegates, addCallback);
}
public static <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> registryType, ResourceLocation optionalDefaultKey, int maxId, int minId, boolean hasDelegates)
{
return PersistentRegistry.ACTIVE.createRegistry(registryName, registryType, optionalDefaultKey, minId, maxId, hasDelegates);
}
public static List<String> injectSnapshot(GameDataSnapshot snapshot, boolean injectFrozenData, boolean isLocalWorld) {
public static List<String> injectSnapshot(GameDataSnapshot snapshot, boolean injectFrozenData, boolean isLocalWorld)
{
FMLLog.info("Injecting existing block and item data into this {} instance", FMLCommonHandler.instance().getEffectiveSide().isServer() ? "server" : "client");
final Map<ResourceLocation, Map<ResourceLocation,Integer[]>> remaps = Maps.newHashMap();
final LinkedHashMap<ResourceLocation, Map<ResourceLocation,Integer>> missing = Maps.newLinkedHashMap();
final Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps = Maps.newHashMap();
final LinkedHashMap<ResourceLocation, Map<ResourceLocation, Integer>> missing = Maps.newLinkedHashMap();
forAllRegistries(PersistentRegistry.ACTIVE, ValidateRegistryFunction.OPERATION);
forAllRegistries(PersistentRegistry.ACTIVE, DumpRegistryFunction.OPERATION);
forAllRegistries(PersistentRegistry.ACTIVE, ResetDelegatesFunction.OPERATION);
// Empty the blockstate map before loading
GameData.getBlockStateIDMap().clear();
// Load the snapshot into the "STAGING" registry
for (Map.Entry<ResourceLocation, GameDataSnapshot.Entry> snapshotEntry : snapshot.entries.entrySet())
{
@ -119,13 +155,17 @@ public class PersistentRegistryManager
// If we have missed data, fire the missing mapping event
List<String> missedMappings = Loader.instance().fireMissingMappingEvent(missing.get(BLOCKS), missing.get(ITEMS), isLocalWorld, remaps.get(BLOCKS), remaps.get(ITEMS));
// If there's still missed mappings, we return, because that's an error
if (!missedMappings.isEmpty()) return missedMappings;
if (!missedMappings.isEmpty())
{
return missedMappings;
}
// If we're loading up the world from disk, we want to add in the new data that might have been provisioned by mods
if (injectFrozenData)
{
// So we load it from the frozen persistent registry
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet())
{
loadFrozenDataToStagingRegistry(remaps, r.getKey(), PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
}
@ -134,7 +174,8 @@ public class PersistentRegistryManager
forAllRegistries(PersistentRegistry.STAGING, ValidateRegistryFunction.OPERATION);
// Load the STAGING registry into the ACTIVE registry
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet())
{
loadRegistry(r.getKey(), PersistentRegistry.STAGING, PersistentRegistry.ACTIVE, PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
@ -151,29 +192,34 @@ public class PersistentRegistryManager
return ImmutableList.of();
}
private static void forAllRegistries(PersistentRegistry registrySet, Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> operation) {
private static void forAllRegistries(PersistentRegistry registrySet, Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> operation)
{
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : registrySet.registries.entrySet())
{
operation.apply(r);
}
}
private static <T> void loadRegistry(ResourceLocation registryName, PersistentRegistry from, PersistentRegistry to, Class<T> regType) {
private static <T> void loadRegistry(ResourceLocation registryName, PersistentRegistry from, PersistentRegistry to, Class<T> regType)
{
FMLControlledNamespacedRegistry<T> fromRegistry = from.getRegistry(registryName, regType);
FMLControlledNamespacedRegistry<T> toRegistry = to.getOrShallowCopyRegistry(registryName, regType, fromRegistry);
toRegistry.set(fromRegistry);
}
private static <T> void loadFrozenDataToStagingRegistry(Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps, ResourceLocation registryName, Class<T> regType) {
private static <T> void loadFrozenDataToStagingRegistry(Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps, ResourceLocation registryName, Class<T> regType)
{
FMLControlledNamespacedRegistry<T> newRegistry = PersistentRegistry.STAGING.getRegistry(registryName, regType);
FMLControlledNamespacedRegistry<T> frozenRegistry = PersistentRegistry.FROZEN.getRegistry(registryName, regType);
newRegistry.loadIds(frozenRegistry.getEntriesNotIn(newRegistry), Maps.<ResourceLocation, Integer>newLinkedHashMap(), remaps.get(registryName), frozenRegistry, registryName);
}
private static <T> void loadPersistentDataToStagingRegistry(boolean injectFrozenData, Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps, LinkedHashMap<ResourceLocation, Map<ResourceLocation, Integer>> missing, Map.Entry<ResourceLocation, GameDataSnapshot.Entry> snapEntry, Class<T> regType) {
private static <T> void loadPersistentDataToStagingRegistry(boolean injectFrozenData, Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps, LinkedHashMap<ResourceLocation, Map<ResourceLocation, Integer>> missing, Map.Entry<ResourceLocation, GameDataSnapshot.Entry> snapEntry, Class<T> regType)
{
ResourceLocation registryName = snapEntry.getKey();
FMLControlledNamespacedRegistry<T> currentRegistry = PersistentRegistry.ACTIVE.getRegistry(registryName, regType);
if (currentRegistry == null) {
if (currentRegistry == null)
{
FMLLog.severe("An unknown persistent registry type {} has been encountered. This Forge instance cannot understand it.", registryName);
StartupQuery.abort();
}
@ -192,17 +238,23 @@ public class PersistentRegistryManager
newRegistry.loadIds(snapshotEntry.ids, missing.get(registryName), remaps.get(registryName), currentRegistry, registryName);
}
public static boolean isFrozen(FMLControlledNamespacedRegistry<?> registry) {
public static boolean isFrozen(FMLControlledNamespacedRegistry<?> registry)
{
return PersistentRegistry.FROZEN.containsRegistry(registry);
}
public static void revertToFrozen() {
if (!PersistentRegistry.FROZEN.isPopulated()) {
public static void revertToFrozen()
{
if (!PersistentRegistry.FROZEN.isPopulated())
{
FMLLog.warning("Can't revert to frozen GameData state without freezing first.");
} else {
}
else
{
FMLLog.fine("Reverting to frozen data state.");
}
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet())
{
loadRegistry(r.getKey(), PersistentRegistry.FROZEN, PersistentRegistry.ACTIVE, PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
// the id mapping has reverted, fire remap events for those that care about id changes
@ -211,15 +263,18 @@ public class PersistentRegistryManager
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
}
public static void freezeData() {
public static void freezeData()
{
FMLLog.fine("Freezing block and item id maps");
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet())
{
loadRegistry(r.getKey(), PersistentRegistry.ACTIVE, PersistentRegistry.FROZEN, PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
forAllRegistries(PersistentRegistry.FROZEN, ValidateRegistryFunction.OPERATION);
}
public static List<String> processIdRematches(Iterable<FMLMissingMappingsEvent.MissingMapping> missedMappings, boolean isLocalWorld, Map<ResourceLocation, Integer[]> remapBlocks, Map<ResourceLocation, Integer[]> remapItems) {
public static List<String> processIdRematches(Iterable<FMLMissingMappingsEvent.MissingMapping> missedMappings, boolean isLocalWorld, Map<ResourceLocation, Integer[]> remapBlocks, Map<ResourceLocation, Integer[]> remapItems)
{
List<String> failed = Lists.newArrayList();
List<String> ignored = Lists.newArrayList();
List<String> warned = Lists.newArrayList();
@ -227,64 +282,90 @@ public class PersistentRegistryManager
final PersistentRegistry staging = PersistentRegistry.STAGING;
final PersistentRegistry active = PersistentRegistry.ACTIVE;
for (FMLMissingMappingsEvent.MissingMapping remap : missedMappings) {
for (FMLMissingMappingsEvent.MissingMapping remap : missedMappings)
{
FMLMissingMappingsEvent.Action action = remap.getAction();
if (action == FMLMissingMappingsEvent.Action.REMAP) {
if (action == FMLMissingMappingsEvent.Action.REMAP)
{
// block/item re-mapped, finish the registration with the new name/object, but the old id
int currId = -1, newId = -1;
ResourceLocation newName;
if (remap.type == GameRegistry.Type.BLOCK) {
currId = staging.getRegistry(BLOCKS, Block.class).getId((Block) remap.getTarget());
if (remap.type == GameRegistry.Type.BLOCK)
{
currId = staging.getRegistry(BLOCKS, Block.class).getId((Block)remap.getTarget());
newName = active.getRegistry(BLOCKS, Block.class).getNameForObject((Block)remap.getTarget());
FMLLog.fine("The Block %s is being remapped to %s.", remap.name, newName);
newId = staging.getRegistry(BLOCKS,Block.class).add(remap.id, newName, (Block) remap.getTarget());
staging.getRegistry(BLOCKS,Block.class).addAlias(remap.resourceLocation, newName);
} else if (remap.type == GameRegistry.Type.ITEM) {
currId = staging.getRegistry(ITEMS, Item.class).getId((Item) remap.getTarget());
newId = staging.getRegistry(BLOCKS, Block.class).add(remap.id, newName, (Block)remap.getTarget());
staging.getRegistry(BLOCKS, Block.class).addAlias(remap.resourceLocation, newName);
}
else if (remap.type == GameRegistry.Type.ITEM)
{
currId = staging.getRegistry(ITEMS, Item.class).getId((Item)remap.getTarget());
newName = active.getRegistry(ITEMS, Item.class).getNameForObject((Item)remap.getTarget());
FMLLog.fine("The Item %s is being remapped to %s.", remap.name, newName);
newId = staging.getRegistry(ITEMS,Item.class).add(remap.id, newName, (Item) remap.getTarget());
staging.getRegistry(ITEMS,Item.class).addAlias(remap.resourceLocation, newName);
} else {
newId = staging.getRegistry(ITEMS, Item.class).add(remap.id, newName, (Item)remap.getTarget());
staging.getRegistry(ITEMS, Item.class).addAlias(remap.resourceLocation, newName);
}
else
{
// currently not remapping non-blocks and items
continue;
}
if (newId != remap.id) throw new IllegalStateException();
if (currId != newId) {
FMLLog.info("Fixed %s id mismatch %s: %d (init) -> %d (map).", remap.type == GameRegistry.Type.BLOCK ? "block" : "item", newName, currId, newId);
(remap.type == GameRegistry.Type.BLOCK ? remapBlocks : remapItems).put(newName, new Integer[]{currId, newId});
if (newId != remap.id)
{
throw new IllegalStateException();
}
} else if (action == FMLMissingMappingsEvent.Action.BLOCKONLY) {
if (currId != newId)
{
FMLLog.info("Fixed %s id mismatch %s: %d (init) -> %d (map).", remap.type == GameRegistry.Type.BLOCK ? "block" : "item", newName, currId, newId);
(remap.type == GameRegistry.Type.BLOCK ? remapBlocks : remapItems).put(newName, new Integer[] {currId, newId});
}
}
else if (action == FMLMissingMappingsEvent.Action.BLOCKONLY)
{
// Pulled out specifically so the block doesn't get reassigned a new ID just because it's
// Item block has gone away
FMLLog.fine("The ItemBlock %s is no longer present in the game. The residual block will remain", remap.name);
} else {
}
else
{
// block item missing, warn as requested and block the id
if (action == FMLMissingMappingsEvent.Action.DEFAULT) {
if (action == FMLMissingMappingsEvent.Action.DEFAULT)
{
defaulted.add(remap.name);
} else if (action == FMLMissingMappingsEvent.Action.IGNORE) {
}
else if (action == FMLMissingMappingsEvent.Action.IGNORE)
{
ignored.add(remap.name);
} else if (action == FMLMissingMappingsEvent.Action.FAIL) {
}
else if (action == FMLMissingMappingsEvent.Action.FAIL)
{
failed.add(remap.name);
} else if (action == FMLMissingMappingsEvent.Action.WARN) {
}
else if (action == FMLMissingMappingsEvent.Action.WARN)
{
warned.add(remap.name);
}
// prevent the id from being reused later
if (remap.type == GameRegistry.Type.BLOCK) {
if (remap.type == GameRegistry.Type.BLOCK)
{
staging.getRegistry(BLOCKS, Block.class).blockId(remap.id);
} else if (remap.type == GameRegistry.Type.ITEM) {
}
else if (remap.type == GameRegistry.Type.ITEM)
{
staging.getRegistry(ITEMS, Item.class).blockId(remap.id);
}
}
}
if (!defaulted.isEmpty()) {
if (!defaulted.isEmpty())
{
String text = "Forge Mod Loader detected missing blocks/items.\n\n" +
"There are " + defaulted.size() + " missing blocks and items in this save.\n" +
"If you continue the missing blocks/items will get removed.\n" +
@ -294,42 +375,57 @@ public class PersistentRegistryManager
for (String s : defaulted) text += s + "\n";
boolean confirmed = StartupQuery.confirm(text);
if (!confirmed) StartupQuery.abort();
if (!confirmed)
{
StartupQuery.abort();
}
try {
try
{
String skip = System.getProperty("fml.doNotBackup");
if (skip == null || !"true".equals(skip)) {
if (skip == null || !"true".equals(skip))
{
ZipperUtil.backupWorld();
} else {
}
else
{
for (int x = 0; x < 10; x++)
FMLLog.severe("!!!!!!!!!! UPDATING WORLD WITHOUT DOING BACKUP !!!!!!!!!!!!!!!!");
}
} catch (IOException e) {
} catch (IOException e)
{
StartupQuery.notify("The world backup couldn't be created.\n\n" + e);
StartupQuery.abort();
}
warned.addAll(defaulted);
}
if (!failed.isEmpty()) {
if (!failed.isEmpty())
{
FMLLog.severe("This world contains blocks and items that refuse to be remapped. The world will not be loaded");
return failed;
}
if (!warned.isEmpty()) {
if (!warned.isEmpty())
{
FMLLog.warning("This world contains block and item mappings that may cause world breakage");
return failed;
} else if (!ignored.isEmpty()) {
}
else if (!ignored.isEmpty())
{
FMLLog.fine("There were %d missing mappings that have been ignored", ignored.size());
}
return failed;
}
public static GameDataSnapshot takeSnapshot() {
public static GameDataSnapshot takeSnapshot()
{
final GameDataSnapshot snap = new GameDataSnapshot();
forAllRegistries(PersistentRegistry.ACTIVE, new Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void>() {
forAllRegistries(PersistentRegistry.ACTIVE, new Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void>()
{
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input)
{
snap.entries.put(input.getKey(), new GameDataSnapshot.Entry(input.getValue()));
return null;
}
@ -338,25 +434,30 @@ public class PersistentRegistryManager
}
public static class GameDataSnapshot {
public static class Entry {
public static class GameDataSnapshot
{
public static class Entry
{
public final Map<ResourceLocation, Integer> ids;
public final Set<ResourceLocation> substitutions;
public final Map<ResourceLocation, ResourceLocation> aliases;
public final Set<Integer> blocked;
public Entry() {
public Entry()
{
this(new HashMap<ResourceLocation, Integer>(), new HashSet<ResourceLocation>(), new HashMap<ResourceLocation, ResourceLocation>(), new HashSet<Integer>());
}
public Entry(Map<ResourceLocation, Integer> ids, Set<ResourceLocation> substitutions, Map<ResourceLocation, ResourceLocation> aliases, Set<Integer> blocked) {
public Entry(Map<ResourceLocation, Integer> ids, Set<ResourceLocation> substitutions, Map<ResourceLocation, ResourceLocation> aliases, Set<Integer> blocked)
{
this.ids = ids;
this.substitutions = substitutions;
this.aliases = aliases;
this.blocked = blocked;
}
public Entry(FMLControlledNamespacedRegistry<?> registry) {
public Entry(FMLControlledNamespacedRegistry<?> registry)
{
this.ids = Maps.newHashMap();
this.substitutions = Sets.newHashSet();
this.aliases = Maps.newHashMap();
@ -372,34 +473,43 @@ public class PersistentRegistryManager
public final Map<ResourceLocation, Entry> entries = Maps.newHashMap();
}
public static <T> RegistryDelegate<T> makeDelegate(T obj, Class<T> rootClass) {
public static <T> RegistryDelegate<T> makeDelegate(T obj, Class<T> rootClass)
{
return PersistentRegistry.ACTIVE.getRegistry(rootClass).getDelegate(obj, rootClass);
}
private static class DumpRegistryFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> {
private static class DumpRegistryFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void>
{
static final DumpRegistryFunction OPERATION = new DumpRegistryFunction();
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input)
{
input.getValue().dump(input.getKey());
return null;
}
}
private static class ValidateRegistryFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> {
private static class ValidateRegistryFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void>
{
static final ValidateRegistryFunction OPERATION = new ValidateRegistryFunction();
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input)
{
input.getValue().validateContent(input.getKey());
return null;
}
}
private static class ResetDelegatesFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> {
private static class ResetDelegatesFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void>
{
static final ResetDelegatesFunction OPERATION = new ResetDelegatesFunction();
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input)
{
input.getValue().resetSubstitutionDelegates();
return null;
}

View File

@ -19,10 +19,18 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.Validate;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.passive.EntityVillager.*;
import net.minecraft.entity.passive.EntityVillager.EmeraldForItems;
import net.minecraft.entity.passive.EntityVillager.ITradeList;
import net.minecraft.entity.passive.EntityVillager.ItemAndEmeraldToItem;
import net.minecraft.entity.passive.EntityVillager.ListEnchantedBookForEmeralds;
import net.minecraft.entity.passive.EntityVillager.ListEnchantedItemForEmeralds;
import net.minecraft.entity.passive.EntityVillager.ListItemForEmeralds;
import net.minecraft.entity.passive.EntityVillager.PriceInfo;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.EnumDyeColor;
@ -38,14 +46,10 @@ import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Registry for villager trading control
*
* @author cpw
*
*/
public class VillagerRegistry
{
@ -66,7 +70,6 @@ public class VillagerRegistry
* creation so you can insert your own new village pieces
*
* @author cpw
*
*/
public interface IVillageCreationHandler
{
@ -86,6 +89,7 @@ public class VillagerRegistry
/**
* Build an instance of the village component {@link net.minecraft.world.gen.structure.StructureVillagePieces}
*
* @param villagePiece
* @param startPiece
* @param pieces
@ -97,7 +101,7 @@ public class VillagerRegistry
* @param p5
*/
Village buildComponent(StructureVillagePieces.PieceWeight villagePiece, StructureVillagePieces.Start startPiece, List<StructureComponent> pieces, Random random, int p1,
int p2, int p3, EnumFacing facing, int p5);
int p2, int p3, EnumFacing facing, int p5);
}
public static VillagerRegistry instance()
@ -107,6 +111,7 @@ public class VillagerRegistry
/**
* Register your villager id
*
* @param id
*/
@Deprecated // Doesn't work at all.
@ -119,6 +124,7 @@ public class VillagerRegistry
}
newVillagerIds.add(id);
}
/**
* Register a new skin for a villager type
*
@ -184,7 +190,7 @@ public class VillagerRegistry
}
public static Village getVillageComponent(StructureVillagePieces.PieceWeight villagePiece, StructureVillagePieces.Start startPiece, List<StructureComponent> pieces, Random random,
int p1, int p2, int p3, EnumFacing facing, int p5)
int p1, int p2, int p3, EnumFacing facing, int p5)
{
return instance().villageCreationHandlers.get(villagePiece.villagePieceClass).buildComponent(villagePiece, startPiece, pieces, random, p1, p2, p3, facing, p5);
}
@ -193,27 +199,30 @@ public class VillagerRegistry
{
register(prof, -1);
}
private void register(VillagerProfession prof, int id)
{
professions.register(id, prof.name, prof);
}
private boolean hasInit = false;
private FMLControlledNamespacedRegistry<VillagerProfession> professions = PersistentRegistryManager.createRegistry(new ResourceLocation("minecraft:villagerprofessions"), VillagerProfession.class, null, 1024, 0, true);
private FMLControlledNamespacedRegistry<VillagerProfession> professions = PersistentRegistryManager.createRegistry(new ResourceLocation("minecraft:villagerprofessions"), VillagerProfession.class, null, 1024, 0, true, null);
private void init()
{
if (hasInit)
{
return;
}
VillagerProfession prof = new VillagerProfession("minecraft:farmer", "minecraft:textures/entity/villager/farmer.png");
{
register(prof, 0);
(new VillagerCareer(prof, "farmer" )).init(VanillaTrades.trades[0][0]);
(new VillagerCareer(prof, "fisherman" )).init(VanillaTrades.trades[0][1]);
(new VillagerCareer(prof, "shepherd" )).init(VanillaTrades.trades[0][2]);
(new VillagerCareer(prof, "fletcher" )).init(VanillaTrades.trades[0][3]);
(new VillagerCareer(prof, "farmer")).init(VanillaTrades.trades[0][0]);
(new VillagerCareer(prof, "fisherman")).init(VanillaTrades.trades[0][1]);
(new VillagerCareer(prof, "shepherd")).init(VanillaTrades.trades[0][2]);
(new VillagerCareer(prof, "fletcher")).init(VanillaTrades.trades[0][3]);
}
prof = new VillagerProfession("minecraft:librarian", "minecraft:textures/entity/villager/librarian.png");
{
@ -228,9 +237,9 @@ public class VillagerRegistry
prof = new VillagerProfession("minecraft:smith", "minecraft:textures/entity/villager/smith.png");
{
register(prof, 3);
(new VillagerCareer(prof, "armor" )).init(VanillaTrades.trades[3][0]);
(new VillagerCareer(prof, "armor")).init(VanillaTrades.trades[3][0]);
(new VillagerCareer(prof, "weapon")).init(VanillaTrades.trades[3][1]);
(new VillagerCareer(prof, "tool" )).init(VanillaTrades.trades[3][2]);
(new VillagerCareer(prof, "tool")).init(VanillaTrades.trades[3][2]);
}
prof = new VillagerProfession("minecraft:butcher", "minecraft:textures/entity/villager/butcher.png");
{
@ -268,6 +277,7 @@ public class VillagerRegistry
private VillagerProfession profession;
private String name;
private int id;
public VillagerCareer(VillagerProfession parent, String name)
{
this.profession = parent;
@ -283,8 +293,14 @@ public class VillagerRegistry
@Override
public boolean equals(Object o)
{
if (o == this) return true;
if (!(o instanceof VillagerCareer)) return false;
if (o == this)
{
return true;
}
if (!(o instanceof VillagerCareer))
{
return false;
}
VillagerCareer oc = (VillagerCareer)o;
return name.equals(oc.name) && profession == oc.profession;
}
@ -294,7 +310,7 @@ public class VillagerRegistry
* Hook called when spawning a Villager, sets it's profession to a random registered profession.
*
* @param entity The new entity
* @param rand The world's RNG
* @param rand The world's RNG
*/
public static void setRandomProfession(EntityVillager entity, Random rand)
{
@ -312,196 +328,196 @@ public class VillagerRegistry
//Moved to inner class to stop static initializer issues.
//It is nasty I know but it's vanilla.
private static final ITradeList[][][][] trades =
{
{
{
{
new EmeraldForItems(Items.wheat, new PriceInfo(18, 22)),
new EmeraldForItems(Items.potato, new PriceInfo(15, 19)),
new EmeraldForItems(Items.carrot, new PriceInfo(15, 19)),
new ListItemForEmeralds(Items.bread, new PriceInfo(-4, -2))
},
{
new EmeraldForItems(Item.getItemFromBlock(Blocks.pumpkin), new PriceInfo(8, 13)),
new ListItemForEmeralds(Items.pumpkin_pie, new PriceInfo(-3, -2))
},
{
new EmeraldForItems(Item.getItemFromBlock(Blocks.melon_block), new PriceInfo(7, 12)),
new ListItemForEmeralds(Items.apple, new PriceInfo(-5, -7))
},
{
new ListItemForEmeralds(Items.cookie, new PriceInfo(-6, -10)),
new ListItemForEmeralds(Items.cake, new PriceInfo(1, 1))
}
},
{
{
new EmeraldForItems(Items.string, new PriceInfo(15, 20)),
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ItemAndEmeraldToItem(Items.fish, new PriceInfo(6, 6), Items.cooked_fish, new PriceInfo(6, 6))
},
{
new ListEnchantedItemForEmeralds(Items.fishing_rod, new PriceInfo(7, 8))
}
},
{
{
new EmeraldForItems(Item.getItemFromBlock(Blocks.wool), new PriceInfo(16, 22)),
new ListItemForEmeralds(Items.shears, new PriceInfo(3, 4))
},
{
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 0), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 1), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 2), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 3), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 4), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 5), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 6), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 7), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 8), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 9), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 10), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 11), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 12), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 13), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 14), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 15), new PriceInfo(1, 2))
}
},
{
{
new EmeraldForItems(Items.string, new PriceInfo(15, 20)),
new ListItemForEmeralds(Items.arrow, new PriceInfo(-12, -8))
},
{
new ListItemForEmeralds(Items.bow, new PriceInfo(2, 3)),
new ItemAndEmeraldToItem(Item.getItemFromBlock(Blocks.gravel), new PriceInfo(10, 10), Items.flint, new PriceInfo(6, 10))
}
}
},
{
{
{
new EmeraldForItems(Items.paper, new PriceInfo(24, 36)),
new ListEnchantedBookForEmeralds()
},
{
new EmeraldForItems(Items.book, new PriceInfo(8, 10)),
new ListItemForEmeralds(Items.compass, new PriceInfo(10, 12)),
new ListItemForEmeralds(Item.getItemFromBlock(Blocks.bookshelf), new PriceInfo(3, 4))
},
{
new EmeraldForItems(Items.written_book, new PriceInfo(2, 2)),
new ListItemForEmeralds(Items.clock, new PriceInfo(10, 12)),
new ListItemForEmeralds(Item.getItemFromBlock(Blocks.glass), new PriceInfo(-5, -3))
},
{
new ListEnchantedBookForEmeralds()
},
{
new ListEnchantedBookForEmeralds()
},
{
new ListItemForEmeralds(Items.name_tag, new PriceInfo(20, 22))
}
}
},
{
{
{
new EmeraldForItems(Items.rotten_flesh, new PriceInfo(36, 40)),
new EmeraldForItems(Items.gold_ingot, new PriceInfo(8, 10))
},
{
new ListItemForEmeralds(Items.redstone, new PriceInfo(-4, -1)),
new ListItemForEmeralds(new ItemStack(Items.dye, 1, EnumDyeColor.BLUE.getDyeDamage()),
new PriceInfo(-2, -1))
},
{
new ListItemForEmeralds(Items.ender_eye, new PriceInfo(7, 11)),
new ListItemForEmeralds(Item.getItemFromBlock(Blocks.glowstone), new PriceInfo(-3, -1))
},
{
new ListItemForEmeralds(Items.experience_bottle, new PriceInfo(3, 11))
}
}
},
{
{
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListItemForEmeralds(Items.iron_helmet, new PriceInfo(4, 6))
},
{
new EmeraldForItems(Items.iron_ingot, new PriceInfo(7, 9)),
new ListItemForEmeralds(Items.iron_chestplate, new PriceInfo(10, 14))
},
{
new EmeraldForItems(Items.diamond, new PriceInfo(3, 4)),
new ListEnchantedItemForEmeralds(Items.diamond_chestplate, new PriceInfo(16, 19))
},
{
new ListItemForEmeralds(Items.chainmail_boots, new PriceInfo(5, 7)),
new ListItemForEmeralds(Items.chainmail_leggings, new PriceInfo(9, 11)),
new ListItemForEmeralds(Items.chainmail_helmet, new PriceInfo(5, 7)),
new ListItemForEmeralds(Items.chainmail_chestplate, new PriceInfo(11, 15))
}
},
{
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListItemForEmeralds(Items.iron_axe, new PriceInfo(6, 8))
},
{
new EmeraldForItems(Items.iron_ingot, new PriceInfo(7, 9)),
new ListEnchantedItemForEmeralds(Items.iron_sword, new PriceInfo(9, 10))
},
{
new EmeraldForItems(Items.diamond, new PriceInfo(3, 4)),
new ListEnchantedItemForEmeralds(Items.diamond_sword, new PriceInfo(12, 15)),
new ListEnchantedItemForEmeralds(Items.diamond_axe, new PriceInfo(9, 12))
}
},
{
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListEnchantedItemForEmeralds(Items.iron_shovel, new PriceInfo(5, 7))
},
{
new EmeraldForItems(Items.iron_ingot, new PriceInfo(7, 9)),
new ListEnchantedItemForEmeralds(Items.iron_pickaxe, new PriceInfo(9, 11))
},
{
new EmeraldForItems(Items.diamond, new PriceInfo(3, 4)),
new ListEnchantedItemForEmeralds(Items.diamond_pickaxe, new PriceInfo(12, 15))
}
}
},
{
{
{
new EmeraldForItems(Items.porkchop, new PriceInfo(14, 18)),
new EmeraldForItems(Items.chicken, new PriceInfo(14, 18))
},
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListItemForEmeralds(Items.cooked_porkchop, new PriceInfo(-7, -5)),
new ListItemForEmeralds(Items.cooked_chicken, new PriceInfo(-8, -6))
}
},
{
{
new EmeraldForItems(Items.leather, new PriceInfo(9, 12)),
new ListItemForEmeralds(Items.leather_leggings, new PriceInfo(2, 4))
},
{
new ListEnchantedItemForEmeralds(Items.leather_chestplate, new PriceInfo(7, 12))
},
{
new ListItemForEmeralds(Items.saddle, new PriceInfo(8, 10))
}
}
}
};
{
{
{
new EmeraldForItems(Items.wheat, new PriceInfo(18, 22)),
new EmeraldForItems(Items.potato, new PriceInfo(15, 19)),
new EmeraldForItems(Items.carrot, new PriceInfo(15, 19)),
new ListItemForEmeralds(Items.bread, new PriceInfo(-4, -2))
},
{
new EmeraldForItems(Item.getItemFromBlock(Blocks.pumpkin), new PriceInfo(8, 13)),
new ListItemForEmeralds(Items.pumpkin_pie, new PriceInfo(-3, -2))
},
{
new EmeraldForItems(Item.getItemFromBlock(Blocks.melon_block), new PriceInfo(7, 12)),
new ListItemForEmeralds(Items.apple, new PriceInfo(-5, -7))
},
{
new ListItemForEmeralds(Items.cookie, new PriceInfo(-6, -10)),
new ListItemForEmeralds(Items.cake, new PriceInfo(1, 1))
}
},
{
{
new EmeraldForItems(Items.string, new PriceInfo(15, 20)),
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ItemAndEmeraldToItem(Items.fish, new PriceInfo(6, 6), Items.cooked_fish, new PriceInfo(6, 6))
},
{
new ListEnchantedItemForEmeralds(Items.fishing_rod, new PriceInfo(7, 8))
}
},
{
{
new EmeraldForItems(Item.getItemFromBlock(Blocks.wool), new PriceInfo(16, 22)),
new ListItemForEmeralds(Items.shears, new PriceInfo(3, 4))
},
{
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 0), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 1), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 2), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 3), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 4), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 5), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 6), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 7), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 8), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 9), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 10), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 11), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 12), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 13), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 14), new PriceInfo(1, 2)),
new ListItemForEmeralds(new ItemStack(Blocks.wool, 1, 15), new PriceInfo(1, 2))
}
},
{
{
new EmeraldForItems(Items.string, new PriceInfo(15, 20)),
new ListItemForEmeralds(Items.arrow, new PriceInfo(-12, -8))
},
{
new ListItemForEmeralds(Items.bow, new PriceInfo(2, 3)),
new ItemAndEmeraldToItem(Item.getItemFromBlock(Blocks.gravel), new PriceInfo(10, 10), Items.flint, new PriceInfo(6, 10))
}
}
},
{
{
{
new EmeraldForItems(Items.paper, new PriceInfo(24, 36)),
new ListEnchantedBookForEmeralds()
},
{
new EmeraldForItems(Items.book, new PriceInfo(8, 10)),
new ListItemForEmeralds(Items.compass, new PriceInfo(10, 12)),
new ListItemForEmeralds(Item.getItemFromBlock(Blocks.bookshelf), new PriceInfo(3, 4))
},
{
new EmeraldForItems(Items.written_book, new PriceInfo(2, 2)),
new ListItemForEmeralds(Items.clock, new PriceInfo(10, 12)),
new ListItemForEmeralds(Item.getItemFromBlock(Blocks.glass), new PriceInfo(-5, -3))
},
{
new ListEnchantedBookForEmeralds()
},
{
new ListEnchantedBookForEmeralds()
},
{
new ListItemForEmeralds(Items.name_tag, new PriceInfo(20, 22))
}
}
},
{
{
{
new EmeraldForItems(Items.rotten_flesh, new PriceInfo(36, 40)),
new EmeraldForItems(Items.gold_ingot, new PriceInfo(8, 10))
},
{
new ListItemForEmeralds(Items.redstone, new PriceInfo(-4, -1)),
new ListItemForEmeralds(new ItemStack(Items.dye, 1, EnumDyeColor.BLUE.getDyeDamage()),
new PriceInfo(-2, -1))
},
{
new ListItemForEmeralds(Items.ender_eye, new PriceInfo(7, 11)),
new ListItemForEmeralds(Item.getItemFromBlock(Blocks.glowstone), new PriceInfo(-3, -1))
},
{
new ListItemForEmeralds(Items.experience_bottle, new PriceInfo(3, 11))
}
}
},
{
{
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListItemForEmeralds(Items.iron_helmet, new PriceInfo(4, 6))
},
{
new EmeraldForItems(Items.iron_ingot, new PriceInfo(7, 9)),
new ListItemForEmeralds(Items.iron_chestplate, new PriceInfo(10, 14))
},
{
new EmeraldForItems(Items.diamond, new PriceInfo(3, 4)),
new ListEnchantedItemForEmeralds(Items.diamond_chestplate, new PriceInfo(16, 19))
},
{
new ListItemForEmeralds(Items.chainmail_boots, new PriceInfo(5, 7)),
new ListItemForEmeralds(Items.chainmail_leggings, new PriceInfo(9, 11)),
new ListItemForEmeralds(Items.chainmail_helmet, new PriceInfo(5, 7)),
new ListItemForEmeralds(Items.chainmail_chestplate, new PriceInfo(11, 15))
}
},
{
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListItemForEmeralds(Items.iron_axe, new PriceInfo(6, 8))
},
{
new EmeraldForItems(Items.iron_ingot, new PriceInfo(7, 9)),
new ListEnchantedItemForEmeralds(Items.iron_sword, new PriceInfo(9, 10))
},
{
new EmeraldForItems(Items.diamond, new PriceInfo(3, 4)),
new ListEnchantedItemForEmeralds(Items.diamond_sword, new PriceInfo(12, 15)),
new ListEnchantedItemForEmeralds(Items.diamond_axe, new PriceInfo(9, 12))
}
},
{
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListEnchantedItemForEmeralds(Items.iron_shovel, new PriceInfo(5, 7))
},
{
new EmeraldForItems(Items.iron_ingot, new PriceInfo(7, 9)),
new ListEnchantedItemForEmeralds(Items.iron_pickaxe, new PriceInfo(9, 11))
},
{
new EmeraldForItems(Items.diamond, new PriceInfo(3, 4)),
new ListEnchantedItemForEmeralds(Items.diamond_pickaxe, new PriceInfo(12, 15))
}
}
},
{
{
{
new EmeraldForItems(Items.porkchop, new PriceInfo(14, 18)),
new EmeraldForItems(Items.chicken, new PriceInfo(14, 18))
},
{
new EmeraldForItems(Items.coal, new PriceInfo(16, 24)),
new ListItemForEmeralds(Items.cooked_porkchop, new PriceInfo(-7, -5)),
new ListItemForEmeralds(Items.cooked_chicken, new PriceInfo(-8, -6))
}
},
{
{
new EmeraldForItems(Items.leather, new PriceInfo(9, 12)),
new ListItemForEmeralds(Items.leather_leggings, new PriceInfo(2, 4))
},
{
new ListEnchantedItemForEmeralds(Items.leather_chestplate, new PriceInfo(7, 12))
},
{
new ListItemForEmeralds(Items.saddle, new PriceInfo(8, 10))
}
}
}
};
}
}