blob: ee36122ea8df8a1d6a887ba75c9233c461f10045 [file] [log] [blame] [raw]
package li.cil.oc.api
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import scala.reflect.runtime.{universe => ru}
/**
* An object that can be persisted to an NBT tag and restored back from it.
*/
trait Persistable {
/**
* Restores a previous state of the object from the specified NBT tag.
*
* @param nbt the tag to read the state from.
*/
def load(nbt: NBTTagCompound)
/**
* Saves the current state of the object into the specified NBT tag.
* <p/>
* This should write the state in such a way that it can be restored when
* `load` is called with that tag.
*
* @param nbt the tag to save the state to.
*/
def save(nbt: NBTTagCompound)
}
/**
* Allows linking persistable instances to an item stack.
* <p/>
* This is used to track item components. It creates an entry in the item
* stack's tag compound name "component", with a UUID that is used to link
* it to the component instance.
* Each type this is used with has to be registered first. For components, I
* recommend registering them in the constructor of the item the component
* belongs to.
* <p/>
* It is important to note that since there is no way for the persistent
* object registry to know when a persistent object met its ultimate doom,
* entries will live forever, unless they are explicitly `delete`d.
*/
object Persistable {
/**
* Registers a new type valid for lookups.
* <p/>
* The name has to be unique among all registered types. It is similar to
* how TileEntities names have to be unique, since this is used to look
* up the constructor when unpersisting instances.
*
* @param name the name of the type
* @param constructor a function that can be used to create a new instance.
* @tparam T the type of the object.
*/
def add[T <: Persistable : ru.TypeTag](name: String, constructor: () => T): Unit =
instance.foreach(_.add(name, constructor))
/**
* Retrieve the object associated to the specified item stack.
* <p/>
* If there is no instance yet, one will be created.
*
* @param stack the item stack to get the persistent object for.
* @tparam T the type of the object.
* @return the persistent object associated with that item stack.
*/
def get[T <: Persistable : ru.TypeTag](stack: ItemStack): Option[T] =
instance.fold(None: Option[T])(_.get(stack))
/**
* Marks the object associated to the specified item stack for deletion.
* <p/>
* Note that the persisted data is only deleted upon the next world save, to
* avoid discrepancies between the persistent storage and the savegame.
*
* @param stack the item stack to delete the persistent object for.
*/
def delete(stack: ItemStack): Unit =
instance.foreach(_.delete(stack))
// ----------------------------------------------------------------------- //
/** Initialized in pre-init. */
private[oc] var instance: Option[ {
def add[T <: Persistable : ru.TypeTag](name: String, constructor: () => T): Unit
def get[T <: Persistable : ru.TypeTag](stack: ItemStack): Option[T]
def delete(stack: ItemStack): Unit
}] = None
}