Last active
August 29, 2015 14:20
-
-
Save tterrag1098/4ff0a06c6b6cb37b901e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.enderio.core.common.util; | |
import gnu.trove.map.TIntObjectMap; | |
import gnu.trove.map.hash.TIntObjectHashMap; | |
import java.io.File; | |
import java.util.BitSet; | |
import java.util.Iterator; | |
import java.util.Map.Entry; | |
import java.util.Set; | |
import lombok.SneakyThrows; | |
import net.minecraft.nbt.CompressedStreamTools; | |
import net.minecraft.nbt.NBTTagCompound; | |
import net.minecraft.nbt.NBTTagList; | |
import net.minecraftforge.common.DimensionManager; | |
import net.minecraftforge.common.MinecraftForge; | |
import net.minecraftforge.common.util.Constants; | |
import net.minecraftforge.event.world.WorldEvent; | |
import org.apache.commons.lang3.ArrayUtils; | |
import com.google.common.collect.BiMap; | |
import com.google.common.collect.HashBiMap; | |
import com.google.common.collect.Sets; | |
import cpw.mods.fml.common.eventhandler.SubscribeEvent; | |
/** | |
* Untested way to save arbitrary to a game save. The name to ID map will be | |
* hot-swapped when a new save is loaded. | |
*/ | |
public class WorldCache<I> { | |
public static final int MAX_ID = Short.MAX_VALUE; | |
protected String ident; | |
protected boolean locked; | |
protected BitSet usedIDs = new BitSet(MAX_ID); | |
protected Set<Integer> blockedIDs = Sets.newHashSet(); | |
protected BiMap<I, String> objToName = HashBiMap.create(); | |
protected BiMap<String, Integer> nameToID = HashBiMap.create(); | |
public WorldCache(String ident) { | |
this(ident, true); | |
} | |
protected WorldCache(String ident, boolean registerToEventBus) { | |
this.ident = ident; | |
if (registerToEventBus) { | |
MinecraftForge.EVENT_BUS.register(this); | |
} | |
} | |
@SubscribeEvent | |
public void onWorldSave(WorldEvent.Save event) { | |
if (!event.world.isRemote && event.world.provider.dimensionId == 0) { | |
saveData(getSaveFile()); | |
} | |
} | |
@SubscribeEvent | |
@SneakyThrows | |
public void onWorldLoad(WorldEvent.Load event) { | |
if (!event.world.isRemote && event.world.provider.dimensionId == 0) { | |
loadData(getSaveFile()); | |
} | |
locked = true; | |
} | |
@SneakyThrows | |
protected void loadData(File file) { | |
if (!file.createNewFile()) { | |
NBTTagCompound tag = null; | |
try { | |
tag = CompressedStreamTools.read(file); | |
} catch (Exception e) { | |
generateIDs(); | |
return; | |
} | |
if (tag.hasKey("ItemData")) { | |
// name <-> id mappings | |
NBTTagList list = tag.getTagList("ItemData", Constants.NBT.TAG_COMPOUND); | |
for (int i = 0; i < list.tagCount(); i++) { | |
NBTTagCompound dataTag = list.getCompoundTagAt(i); | |
int id = dataTag.getInteger("V"); | |
String name = dataTag.getString("K"); | |
nameToID.put(name, id); | |
if (objToName.values().contains(name)) { | |
usedIDs.set(id, true); | |
} | |
} | |
// blocked ids | |
for (int id : tag.getIntArray("BlockedItemIds")) { | |
blockedIDs.add(id); | |
} | |
blockOldIDs(); | |
mergeNewIDs(); | |
return; | |
} | |
} | |
generateIDs(); | |
} | |
@SneakyThrows | |
protected void saveData(File file) { | |
NBTTagCompound data = new NBTTagCompound(); | |
// name <-> id mappings | |
NBTTagList dataList = new NBTTagList(); | |
for (String key : nameToID.keySet()) { | |
NBTTagCompound tag = new NBTTagCompound(); | |
tag.setString("K", key); | |
tag.setInteger("V", nameToID.get(key)); | |
dataList.appendTag(tag); | |
} | |
data.setTag("ItemData", dataList); | |
// blocked ids | |
data.setIntArray("BlockedItemIds", ArrayUtils.toPrimitive(blockedIDs.toArray(new Integer[0]))); | |
CompressedStreamTools.write(data, file); | |
} | |
protected void blockOldIDs() { | |
for (String s : nameToID.keySet()) { | |
if (!objToName.containsValue(s)) { | |
blockedIDs.add(nameToID.get(s)); | |
} | |
} | |
Iterator<String> iter = nameToID.keySet().iterator(); | |
while (iter.hasNext()) { | |
if (blockedIDs.contains(nameToID.get(iter.next()))) { | |
iter.remove(); | |
} | |
} | |
} | |
protected void mergeNewIDs() { | |
for (String s : objToName.values()) { | |
Integer id = nameToID.get(s); | |
if (id != null) { | |
setID(s); | |
} | |
} | |
} | |
protected void generateIDs() { | |
for (Entry<I, String> e : objToName.entrySet()) { | |
if (!nameToID.containsKey(e.getValue())) { | |
setID(e.getValue()); | |
} | |
} | |
} | |
protected int getNextAvailableID(String name) { | |
Integer nextID = nameToID.get(name); | |
if (nextID != null) { | |
return nextID; | |
} else { | |
nextID = usedIDs.nextClearBit(0); | |
} | |
while (blockedIDs.contains(nextID) || nameToID.values().contains(nextID)) { | |
usedIDs.nextClearBit(nextID++); | |
} | |
return nextID; | |
} | |
protected void setID(String name) { | |
setID(name, getNextAvailableID(name)); | |
} | |
protected void setID(String name, int id) { | |
nameToID.put(name, id); | |
usedIDs.set(id, true); | |
} | |
@SneakyThrows | |
protected File getSaveFile() { | |
return new File(DimensionManager.getCurrentSaveRootDirectory().getAbsolutePath() + "/" + ident + ".json"); | |
} | |
public void addObject(I object, String name) { | |
if (locked) { | |
throw new IllegalStateException("Cannot add to world cache after world load!"); | |
} | |
objToName.put(object, name); | |
} | |
public int getID(I obj) { | |
return nameToID.get(getName(obj)); | |
} | |
public String getName(I obj) { | |
return objToName.get(obj); | |
} | |
public I getObject(int id) { | |
return getObject(nameToID.inverse().get(id)); | |
} | |
public I getObject(String string) { | |
return objToName.inverse().get(string); | |
} | |
public Iterator<I> getObjects() { | |
return objToName.keySet().iterator(); | |
} | |
public TIntObjectMap<I> getEnumeratedObjects() { | |
TIntObjectMap<I> ret = new TIntObjectHashMap<I>(); | |
for (int i = 0; i <= MAX_ID && usedIDs.nextSetBit(i) >= 0; i++) { | |
if (usedIDs.get(i)) { | |
ret.put(i, getObject(i)); | |
} | |
} | |
return ret; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment