Here we outline a few key API classes/interfaces.
This is the structure definition of your multi. You will have one `IStructureDefinition` for each multi.
These are how you define which block will be accepted.
This is the standard library of {@link com.gtnewhorizon.structurelib.structure.IStructureElement IStructureElement}s. The Standard Library contains structure elements that handle basic block element and elements that allow composing these basic elements.
This interface should be implemented by tile entities that support creative autoplacing and hint particle emitting. You will usually want to have a backing {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition IStructureDefinition} and call its {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int) build()} or {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int) hints()} method here.
This interface is an enhancement over {@link com.gtnewhorizon.structurelib.alignment.constructable.IConstructable IConstructable}. If your tile entities also support survival autoplacing then you should implement this. You will usually want to have a backing {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition IStructureDefinition} and call its {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#survivalBuild(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int, int, IItemSource, EntityPlayerMP, boolean) survivalBuild()}.
This interface should be implemented on tile entities that will delegate all constructable or survival construable functionality to some other class. This is mostly only to support gregtech meta tile entity system.
Return null if the delegate does not exist.
This class backs the standard implementations of {@link com.gtnewhorizon.structurelib.structure.IItemSource}. You might want to register new inventory provider or inventory extractor there to facilitate survival auto place.
These interfaces will be used to implement rotation. Provide a framework to rotate the block. You can skip this if you store ExtendedFacing and do rotation in other means.
This class contains the accessors for channel data held on a trigger item. See below for more information.
This class contains the low level utility used for implementing new {@link com.gtnewhorizon.structurelib.structure.IStructureElement}. You will also need methods in this class to while implementing rotation.
IF THERE IS A SAME NAMED METHOD IN OTHER CLASS, ONLY USE METHODS FOUND IN THIS CLASS, NOT OTHER CLASS. This abstraction is necessary so we can change how underlying code work (e.g. how hint particles are rendered) without breaking client code.
This class is the base class of all events that will be posted while a IStructureDefinition are visited. These events are disabled by default, and can be enabled by calling {@link com.gtnewhorizon.structurelib.StructureLibAPI#enableInstrument(Object)}. To receive these events, register an event handler to {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}. Handlers should filter the events received by {@link com.gtnewhorizon.structurelib.StructureEvent#getInstrumentIdentifier()}.
These events are intended for third party tools to inspect structure details. Normal users should not use these at all.
Context Object are what you pass to {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)} and alike as first parameter. It will hold the necessary states for {@link com.gtnewhorizon.structurelib.structure.IStructureElement}. It's usually, but not necessarily, the multiblock controller.
Standard structure element library offers method to switch context objects if needed.
Trigger Item is the item used to trigger hint spawn, creative build and survival auto place. The trigger item will be passed to relevant classes as an indicator of structure tier. The item type and stack tag compound of this item stack are opaque objects that should not be parsed.
StructureLib comes with a trigger item implementation. It does register it to the game registries, but does not come with a recipe. Usually there is no reason to reimplement this on your own.
Trigger item carries the player's choice of structure tier by its stack size. When one multi have multiple tiered component that can have interleaving tier, this becomes an obnoxious restriction, as one ItemStack cannot have two stack sizes at the same time. Here we use the channels to bypass this restriction.
Basically, channels are information stored on the trigger item's NBT tags. One trigger item can carry multiple channels. Each channel can be identified with lower case strings and has the value being one positive Java int. There will be one and only one master channel and 0 or more sub channel. When a non-existent sub channel is queried, master channel will be used instead to fill its place.
Structure Definition Author and/or Structure Element Author can choose whether they use a channel and which channel to use.
Structure Element Author will usually not need to consider channels, i.e. proceed as if this concept does not exist, unless it must take input from multiple channels.
Structure Definition Author will consider how to map each channel to each tiered component. He will be using `com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel` to direct structure element on which channel to use. Conceptually, it will return an ItemStack with the master channel being the value of selected channel. In implementation, withChannel will return a new ItemStack with same item, nbt but different stack size.
It's worth mentioning that the returned new ItemStack will still have all the channel data on it, so a multi-channel structure element can still query the channel it wants just fine. It is however impossible to recover the original master channel.
GT++ Chemical Plant is a multi with 4 distinctly tiered component.
It will use
.addElement('a', shellStructureElement())
.addElement('b', withChannel("casing", machineCasingStructureElement()))
.addElement('c', withChannel("pipe", pipeCasingStructureElement()))
.addElement('d', withChannel("coil", coilStructureElement()))
whereas all these structure elements are designed without considering channels whatsoever
Suppose your hatch element has a required facing and can accept arbitrary meta tile entity, so it will need both meta id and facing input.
It will use
Its code will then look like
import com.gtnewhorizon.structurelib.structure.IStructureElement;
public class MyHatchElement<T> implements IStructureElement<T> {
//...
{@literal @}Override
public PlaceResult survivalPlaceBlock(
Object o,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (shouldSkip(o, world, x, y, z)) return PlaceResult.SKIP;
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
ItemStack taken = s.takeOne(filterByID(ChannelDataAccessor.getChannelData(trigger, "id")).andThen(filterByFacing(trigger.stackSize)));
if (taken == null) return PlaceResult.REJECT;
return StructureUtility.survivalPlaceBlock(taken, ItemStackPredicate.NBTMode.IGNORE, null, true, world, x, y, z, s, actor);
}
}
The code for placeBlock() and spawnHint() will be left as an exercise for the reader.
StructureLib support third party tools to poke into structure's internals via events. This is done by listening to {@link com.gtnewhorizon.structurelib.StructureEvent} and its subclasses on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS forge main event bus}.
Please refer to {@link com.gtnewhorizon.structurelib.StructureEvent} to see what events are available.