package net.glowstone.io.structure;
import net.glowstone.GlowWorld;
import net.glowstone.generator.structures.GlowStructure;
import net.glowstone.util.nbt.CompoundTag;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* The class responsible for mapping structure types to their storage methods
* and reading and writing structure data using those storage methods.
*/
public final class StructureStorage {
/**
* A table which maps structure ids to compound readers. This is generally used
* to map stored structures to actual structures.
*/
private static final Map<String, StructureStore<?>> idTable = new HashMap<>();
/**
* A table which maps structures to stores. This is generally used to map
* structures being stored.
*/
private static final Map<Class<? extends GlowStructure>, StructureStore<?>> classTable = new HashMap<>();
/*
* Populates the maps with stores.
*/
static {
bind(new TempleStore());
//bind(new VillageStore());
//bind(new StrongholdStore());
//bind(new MineshaftStore());
}
private StructureStorage() {
}
/**
* Binds a store by adding entries for it to the tables.
*
* @param store The store object.
* @param <T> The type of structure.
*/
private static <T extends GlowStructure> void bind(StructureStore<T> store) {
idTable.put(store.getId(), store);
classTable.put(store.getType(), store);
}
/**
* Returns all known structure stores.
*
* @return A collection containing all structure stores.
*/
public static Collection<StructureStore<?>> getStructureStores() {
return Collections.unmodifiableCollection(idTable.values());
}
/**
* Load a structure in the given world from the given data tag.
*
* @param world The target world.
* @param compound The tag to load from.
* @return The newly constructed structure.
* @throws IllegalArgumentException if there is an error in the data.
*/
public static GlowStructure loadStructure(GlowWorld world, CompoundTag compound) {
// look up the store by the tag's id
if (!compound.isString("id")) {
throw new IllegalArgumentException("Structure has no type");
}
StructureStore<?> store = idTable.get(compound.getString("id"));
if (store == null) {
throw new IllegalArgumentException("Unknown structure type: \"" + compound.getString("id") + "\"");
}
int x = 0, z = 0;
if (compound.isInt("ChunkX")) {
x = compound.getInt("ChunkX");
}
if (compound.isInt("ChunkZ")) {
z = compound.getInt("ChunkZ");
}
return createStructure(world, x, z, store, compound);
}
/**
* Save a structure data to the given compound tag.
*
* @param structure The structure to save.
* @param compound The target tag.
* @return The structure store for the saved structure.
*/
public static StructureStore<GlowStructure> saveStructure(GlowStructure structure, CompoundTag compound) {
// look up the store for the structure
StructureStore<?> store = classTable.get(structure.getClass());
if (store == null) {
throw new IllegalArgumentException("Unknown structure type to save: \"" + structure.getClass() + "\"");
}
compound.putString("id", store.getId());
compound.putInt("ChunkX", structure.getChunkX());
compound.putInt("ChunkZ", structure.getChunkZ());
StructureStore<GlowStructure> baseStore = getBaseStore(store);
baseStore.save(structure, compound);
return baseStore;
}
/**
* Helper method to call StructureStore methods for type safety.
*/
private static <T extends GlowStructure> T createStructure(GlowWorld world, int chunkX, int chunkZ, StructureStore<T> store, CompoundTag compound) {
T structure = store.createStructure(world, chunkX, chunkZ);
store.load(structure, compound);
return structure;
}
/**
* Unsafe-cast an unknown StructureStore to the base type.
*/
@SuppressWarnings("unchecked")
private static StructureStore<GlowStructure> getBaseStore(StructureStore<?> store) {
return (StructureStore<GlowStructure>) store;
}
}