Skip to content

Instantly share code, notes, and snippets.

@copygirl
Last active September 3, 2016 15:41
Show Gist options
  • Select an option

  • Save copygirl/53f94373c0f6901a87b9dad0b934423c to your computer and use it in GitHub Desktop.

Select an option

Save copygirl/53f94373c0f6901a87b9dad0b934423c to your computer and use it in GitHub Desktop.
/** Represents arbitrary data that can be added to any object that implements IComponentsProvider.
* For example: Block, Item, Entity, ItemStack, Enchantment, Biome, ...
*
* Components are required to have an empty public constructor so they can be loaded / saved and
* getOrCreate can be used. */
public interface IComponent {
/** Serializes (saves) this component as an NBT tag.
* If null is returned, the component won't be saved. */
Tag serialize() { return null; }
/** Deserializes (loads) this component from an NBT tag.
* If false is returned, the component will be dropped. */
boolean deserialize(Tag tag) { return false; }
}
/** Holds the components for an IComponentsProvider. */
public class ComponentContainer implements Iterable<IComponent> {
public static final String TAG_NAME = "fabric:components";
private final IComponentsProvider owner;
private final Map<Class<? extends IComponent>, IComponent> map;
public ComponentContainer(IComponentsProvider owner) {
this.owner = owner;
this.map = new HashMap<>();
}
/** Gets a component of type T or null if it's not present. */
public <T extends IComponent> T get(Class<T> componentClass) {
return map.get(componentClass);
}
/** Sets a component of type T, returning the previous value, null if none. */
public <T extends IComponent> T set(Class<T> componentClass, @Nullable T component) {
IComponent previous = ((component != null)
? map.put(componentClass, component)
: map.remove(componentClass));
if (previous != null) owner.onComponentRemoved(previous);
if (component != null) owner.onComponentAdded(component);
return previous;
}
/** Adds a component of type T, returning the previous value, null if none. */
public <T extends IComponent> T add(T component) {
return set((Class<T>)component.getClass(), component);
}
/** Removes a component of type T, returning the previous value, null if none. */
public <T extends IComponent> T remove(Class<T> componentClass) {
return set(componentClass, null);
}
/** Gets a component of type T or creates one if it's not present. */
public <T extends IComponent> T getOrCreate(Class<T> componentClass) {
T component = get<T>(componentClass);
if (component == null)
component = componentClass.newInstance(); // TODO: Wrap with try/catch.
return component;
}
public void serializeTag(TagCompound root) {
TagCompound compound = new TagCompound();
for (Map.Entry<Class, IComponent> entry : map.entrySet()) {
String className = entry.getKey().getClass().getName();
IComponent component = entry.getValue();
try {
Tag componentTag = component.serialize();
if (componentTag == null) continue;
compound.setTag(className, componentTag);
} catch (Exception ex) {
// TODO: Failed to save component.
}
}
if (!compound.isEmpty)
root.setTag(TAG_NAME, compound);
}
public void deserializeTag(TagCompound root) {
Tag tag = root.getTag(TAG_NAME);
if ((tag == null) || (tag.getType() != 10)) return;
TagCompound compound = (TagCompound)tag;
for (String className : compound.getKeys()) {
Tag componentTag = component.getTag(className);
try {
Class componentClass = Class.forName(className);
IComponent component = (IComponent)componentClass.newInstance();
if (!component.deserialize(componentTag)) continue;
components.put(className, component);
} catch (Exception ex) {
// TODO: Failed to load component.
}
}
}
public Iterator<IComponent> iterator() {
return map.valueSet().iterator();
}
}
public interface IComponentsProvider {
/** Gets this IComponentsProvider's components. */
ComponentContainer components();
/** Called when a component is added to this IComponentsProvider. */
void onComponentAdded(IComponent component);
/** Called when a component is removed from this IComponentsProvider. */
void onComponentRemoved(IComponent component);
}
public class ComponentsProviderMixin implements IComponentsProvider {
private final ComponentContainer components;
public ComponentsProviderMixin() { components = new ComponentContainer(this); }
public ComponentContainer components() { return components; }
public void onComponentAdded(IComponent component) { }
public void onComponentRemoved(IComponent component) { }
}
/* ======================= *
* [[ Example Component ]] *
* ======================= */
public class BackpackComponent implements IComponent {
private ItemStack backpack;
public Tag serialize() {
TagCompound compound = new TagCompound();
compound.setTag("backpack", backpack.serialize(new TagCompound()));
return compound;
}
public boolean deserialize(Tag tag) {
TagCompound compound = (TagCompound)tag;
backpack = new ItemStack(compound.getTag("backpack"));
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment