2013-12-09 06:22:24 +00:00
|
|
|
package cpw.mods.fml.common.registry;
|
|
|
|
|
|
|
|
import gnu.trove.map.hash.TIntIntHashMap;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.BitSet;
|
2013-12-10 02:36:49 +00:00
|
|
|
import java.util.List;
|
2013-12-09 06:22:24 +00:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map.Entry;
|
2013-12-10 02:36:49 +00:00
|
|
|
import net.minecraft.util.ObjectIntIdentityMap;
|
|
|
|
import net.minecraft.util.RegistryNamespaced;
|
2013-12-09 06:22:24 +00:00
|
|
|
import com.google.common.collect.BiMap;
|
|
|
|
import com.google.common.collect.HashBiMap;
|
2013-12-24 05:47:10 +00:00
|
|
|
import com.google.common.collect.ImmutableBiMap;
|
2013-12-09 06:22:24 +00:00
|
|
|
import com.google.common.collect.Maps;
|
2013-12-10 02:36:49 +00:00
|
|
|
import com.google.common.primitives.Ints;
|
2013-12-26 17:41:49 +00:00
|
|
|
import cpw.mods.fml.common.FMLLog;
|
2013-12-09 06:22:24 +00:00
|
|
|
import cpw.mods.fml.common.Loader;
|
|
|
|
import cpw.mods.fml.common.ModContainer;
|
|
|
|
|
|
|
|
public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
|
2013-12-10 02:36:49 +00:00
|
|
|
static class FMLObjectIntIdentityMap extends ObjectIntIdentityMap {
|
2013-12-24 05:47:10 +00:00
|
|
|
private TIntIntHashMap frozenMap;
|
2013-12-09 06:22:24 +00:00
|
|
|
private TIntIntHashMap oldMap;
|
|
|
|
private TIntIntHashMap newMap;
|
2013-12-24 05:47:10 +00:00
|
|
|
private ArrayList<Integer> frozenIndex;
|
2013-12-09 06:22:24 +00:00
|
|
|
private ArrayList<Integer> oldIndex;
|
|
|
|
private ArrayList<Integer> newIndex;
|
|
|
|
|
|
|
|
public FMLObjectIntIdentityMap()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean containsID(int id)
|
|
|
|
{
|
|
|
|
return func_148744_b(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object get(int id)
|
|
|
|
{
|
|
|
|
return func_148745_a(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int get(Object obj)
|
|
|
|
{
|
|
|
|
return func_148747_b(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
void beginSwap()
|
|
|
|
{
|
|
|
|
oldMap = field_148749_a;
|
|
|
|
newMap = new TIntIntHashMap(256, 0.5F, -1, -1);
|
|
|
|
oldIndex = (ArrayList<Integer>) field_148748_b;
|
|
|
|
newIndex = new ArrayList<Integer>(oldIndex.size());
|
|
|
|
}
|
|
|
|
|
2013-12-24 05:47:10 +00:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
void freezeMap()
|
|
|
|
{
|
|
|
|
frozenMap = new TIntIntHashMap(field_148749_a);
|
|
|
|
frozenIndex = new ArrayList<Integer>(field_148748_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void revertToFrozen()
|
|
|
|
{
|
|
|
|
field_148749_a = frozenMap;
|
|
|
|
field_148748_b = frozenIndex;
|
|
|
|
}
|
2013-12-09 06:22:24 +00:00
|
|
|
void completeSwap()
|
|
|
|
{
|
|
|
|
field_148749_a = newMap;
|
|
|
|
field_148748_b = newIndex;
|
|
|
|
oldIndex = newIndex = null;
|
|
|
|
oldMap = newMap = null;
|
|
|
|
}
|
|
|
|
|
2013-12-18 16:15:03 +00:00
|
|
|
void revertSwap()
|
|
|
|
{
|
|
|
|
field_148749_a = oldMap;
|
|
|
|
field_148748_b = oldIndex;
|
|
|
|
oldIndex = newIndex = null;
|
|
|
|
oldMap = newMap = null;
|
|
|
|
}
|
|
|
|
|
2013-12-09 06:22:24 +00:00
|
|
|
void putNew(int id, Object item)
|
|
|
|
{
|
|
|
|
field_148749_a = newMap;
|
|
|
|
field_148748_b = newIndex;
|
|
|
|
super.func_148746_a(item, id);
|
|
|
|
field_148749_a = oldMap;
|
|
|
|
field_148748_b = oldIndex;
|
|
|
|
}
|
2013-12-10 02:36:49 +00:00
|
|
|
|
|
|
|
List<Integer> usedIds()
|
|
|
|
{
|
|
|
|
return Ints.asList(field_148749_a.keys());
|
|
|
|
}
|
2013-12-18 16:15:03 +00:00
|
|
|
|
2013-12-09 06:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private final Class<I> superType;
|
|
|
|
private String optionalDefaultName;
|
|
|
|
private I optionalDefaultObject;
|
|
|
|
|
|
|
|
private BiMap<String,Integer> namedIds = HashBiMap.create();
|
2013-12-24 05:47:10 +00:00
|
|
|
private BiMap<String,Integer> frozenIds;
|
2013-12-10 02:36:49 +00:00
|
|
|
private Map<String,Integer> transactionalNamedIds;
|
2013-12-26 17:41:49 +00:00
|
|
|
private BitSet transactionalAvailabilityMap;
|
2013-12-09 06:22:24 +00:00
|
|
|
private BitSet availabilityMap;
|
2014-02-01 11:05:33 +00:00
|
|
|
int maxId;
|
2013-12-09 06:22:24 +00:00
|
|
|
private int minId;
|
2013-12-10 02:36:49 +00:00
|
|
|
private char discriminator;
|
2013-12-09 06:22:24 +00:00
|
|
|
|
2013-12-10 02:36:49 +00:00
|
|
|
public FMLControlledNamespacedRegistry(String optionalDefault, int maxIdValue, int minIdValue, Class<I> type, char discriminator)
|
2013-12-09 06:22:24 +00:00
|
|
|
{
|
|
|
|
this.superType = type;
|
2013-12-10 02:36:49 +00:00
|
|
|
this.discriminator = discriminator;
|
2013-12-09 06:22:24 +00:00
|
|
|
this.optionalDefaultName = optionalDefault;
|
|
|
|
this.availabilityMap = new BitSet(maxIdValue);
|
|
|
|
this.maxId = maxIdValue;
|
|
|
|
this.minId = minIdValue;
|
|
|
|
this.field_148759_a = new FMLObjectIntIdentityMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void func_148756_a(int id, String name, Object thing)
|
|
|
|
{
|
2014-01-20 20:09:24 +00:00
|
|
|
FMLLog.finer("Add : %s %d %s", name, id, thing);
|
2013-12-09 06:22:24 +00:00
|
|
|
add(id, name, superType.cast(thing));
|
|
|
|
}
|
|
|
|
|
2013-12-24 05:47:10 +00:00
|
|
|
int swap(int id, String name, I thing)
|
|
|
|
{
|
2014-01-20 20:09:24 +00:00
|
|
|
FMLLog.fine("Swap : %s %d %s", name, id, thing);
|
2013-12-26 17:41:49 +00:00
|
|
|
BitSet temporary = availabilityMap;
|
|
|
|
availabilityMap = transactionalAvailabilityMap;
|
|
|
|
|
|
|
|
int idToUse = id;
|
|
|
|
if (id == 0 || availabilityMap.get(id))
|
|
|
|
{
|
|
|
|
idToUse = availabilityMap.nextClearBit(minId);
|
|
|
|
}
|
|
|
|
if (idToUse >= maxId)
|
|
|
|
{
|
|
|
|
throw new RuntimeException(String.format("Invalid id %s - not accepted",id));
|
|
|
|
}
|
|
|
|
|
|
|
|
namedIds.forcePut(func_148755_c(name),idToUse);
|
|
|
|
reassignMapping(name, idToUse);
|
|
|
|
useSlot(idToUse);
|
|
|
|
availabilityMap = temporary;
|
2014-01-20 20:09:24 +00:00
|
|
|
FMLLog.fine("Swap : %s %d %s", name, idToUse, thing);
|
2013-12-26 17:41:49 +00:00
|
|
|
return idToUse;
|
2013-12-24 05:47:10 +00:00
|
|
|
}
|
2013-12-10 02:36:49 +00:00
|
|
|
public int add(int id, String name, I thing)
|
2013-12-09 06:22:24 +00:00
|
|
|
{
|
|
|
|
if (name.equals(optionalDefaultName))
|
|
|
|
{
|
|
|
|
this.optionalDefaultObject = thing;
|
|
|
|
}
|
|
|
|
|
|
|
|
int idToUse = id;
|
2013-12-10 02:36:49 +00:00
|
|
|
if (id == 0 || availabilityMap.get(id))
|
2013-12-09 06:22:24 +00:00
|
|
|
{
|
|
|
|
idToUse = availabilityMap.nextClearBit(minId);
|
|
|
|
}
|
|
|
|
if (idToUse >= maxId)
|
|
|
|
{
|
|
|
|
throw new RuntimeException(String.format("Invalid id %s - not accepted",id));
|
|
|
|
}
|
|
|
|
|
|
|
|
ModContainer mc = Loader.instance().activeModContainer();
|
2013-12-10 02:36:49 +00:00
|
|
|
if (mc != null)
|
|
|
|
{
|
|
|
|
String prefix = mc.getModId();
|
|
|
|
name = prefix + ":"+ name;
|
|
|
|
}
|
2013-12-26 17:41:49 +00:00
|
|
|
namedIds.forcePut(func_148755_c(name),idToUse);
|
2013-12-09 06:22:24 +00:00
|
|
|
super.func_148756_a(idToUse, name, thing);
|
2013-12-10 02:36:49 +00:00
|
|
|
useSlot(idToUse);
|
2014-01-20 20:09:24 +00:00
|
|
|
FMLLog.finer("Add : %s %d %s", name, idToUse, thing);
|
2013-12-10 02:36:49 +00:00
|
|
|
return idToUse;
|
2013-12-09 06:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public I func_82594_a(String name)
|
|
|
|
{
|
|
|
|
I object = superType.cast(super.func_82594_a(name));
|
|
|
|
return object == null ? this.optionalDefaultObject : object;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public I func_148754_a(int id)
|
|
|
|
{
|
|
|
|
I object = superType.cast(super.func_148754_a(id));
|
|
|
|
return object == null ? this.optionalDefaultObject : object;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-10 02:36:49 +00:00
|
|
|
private FMLObjectIntIdentityMap idMap()
|
2013-12-09 06:22:24 +00:00
|
|
|
{
|
2013-12-10 02:36:49 +00:00
|
|
|
return (FMLObjectIntIdentityMap) field_148759_a;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
private BiMap<String,I> nameMap()
|
|
|
|
{
|
|
|
|
return (BiMap<String,I>) field_82596_a;
|
|
|
|
}
|
2013-12-09 06:22:24 +00:00
|
|
|
|
2013-12-10 02:36:49 +00:00
|
|
|
void beginIdSwap()
|
|
|
|
{
|
|
|
|
idMap().beginSwap();
|
|
|
|
transactionalNamedIds = Maps.newHashMap();
|
2013-12-26 17:41:49 +00:00
|
|
|
transactionalAvailabilityMap = new BitSet();
|
2013-12-10 02:36:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void reassignMapping(String name, int newId)
|
|
|
|
{
|
|
|
|
Object item = nameMap().get(name);
|
|
|
|
idMap().putNew(newId, item);
|
|
|
|
transactionalNamedIds.put(name,newId);
|
2013-12-26 17:41:49 +00:00
|
|
|
transactionalAvailabilityMap.set(newId);
|
2013-12-10 02:36:49 +00:00
|
|
|
}
|
|
|
|
|
2013-12-24 05:47:10 +00:00
|
|
|
void freezeMap()
|
|
|
|
{
|
|
|
|
if (frozenIds == null)
|
|
|
|
{
|
|
|
|
frozenIds = ImmutableBiMap.copyOf(namedIds);
|
|
|
|
idMap().freezeMap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void revertToFrozen()
|
|
|
|
{
|
|
|
|
namedIds = HashBiMap.create(frozenIds);
|
|
|
|
idMap().revertToFrozen();
|
|
|
|
}
|
|
|
|
|
|
|
|
Map<String,Integer> getMissingMappings()
|
|
|
|
{
|
|
|
|
return Maps.difference(frozenIds, transactionalNamedIds).entriesOnlyOnLeft();
|
|
|
|
}
|
2013-12-10 02:36:49 +00:00
|
|
|
void completeIdSwap()
|
|
|
|
{
|
|
|
|
idMap().completeSwap();
|
|
|
|
namedIds.clear();
|
|
|
|
namedIds.putAll(transactionalNamedIds);
|
|
|
|
transactionalNamedIds = null;
|
2013-12-09 06:22:24 +00:00
|
|
|
}
|
|
|
|
|
2013-12-18 16:15:03 +00:00
|
|
|
void revertSwap()
|
|
|
|
{
|
|
|
|
idMap().revertSwap();
|
|
|
|
transactionalNamedIds = null;
|
|
|
|
}
|
|
|
|
|
2013-12-09 06:22:24 +00:00
|
|
|
public I get(int id)
|
|
|
|
{
|
|
|
|
return func_148754_a(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
public I get(String name)
|
|
|
|
{
|
|
|
|
return func_82594_a(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getId(I thing)
|
|
|
|
{
|
|
|
|
return func_148757_b(thing);
|
|
|
|
}
|
2013-12-10 02:36:49 +00:00
|
|
|
|
2013-12-09 06:22:24 +00:00
|
|
|
public void serializeInto(Map<String, Integer> idMapping)
|
|
|
|
{
|
|
|
|
for (Entry<String, Integer> id: namedIds.entrySet())
|
|
|
|
{
|
2013-12-10 02:36:49 +00:00
|
|
|
idMapping.put(discriminator+id.getKey(), id.getValue());
|
2013-12-09 06:22:24 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-10 02:36:49 +00:00
|
|
|
|
|
|
|
public void useSlot(int id)
|
|
|
|
{
|
|
|
|
if (id >= maxId) return;
|
|
|
|
availabilityMap.set(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
List<Integer> usedIds()
|
|
|
|
{
|
|
|
|
return ((FMLObjectIntIdentityMap)field_148759_a).usedIds();
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getId(String itemName)
|
|
|
|
{
|
2013-12-24 05:47:10 +00:00
|
|
|
if (namedIds.containsKey(itemName))
|
|
|
|
{
|
|
|
|
return namedIds.get(itemName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2013-12-10 02:36:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean contains(String itemName)
|
|
|
|
{
|
|
|
|
return namedIds.containsKey(itemName);
|
|
|
|
}
|
2013-12-26 17:41:49 +00:00
|
|
|
|
|
|
|
void dump()
|
|
|
|
{
|
|
|
|
for (Entry<String, Integer> entry : namedIds.entrySet())
|
|
|
|
{
|
|
|
|
String name = entry.getKey();
|
|
|
|
Object thing = idMap().get(entry.getValue().intValue());
|
2014-01-20 20:09:24 +00:00
|
|
|
FMLLog.finer("Registry : %s %d %s", name, entry.getValue(), thing);
|
2013-12-26 17:41:49 +00:00
|
|
|
}
|
|
|
|
}
|
2014-02-01 11:05:33 +00:00
|
|
|
|
|
|
|
BitSet slots()
|
|
|
|
{
|
|
|
|
return (BitSet) availabilityMap.clone();
|
|
|
|
}
|
2013-12-09 06:22:24 +00:00
|
|
|
}
|