blob: c03b2251d20e08b389cc5cf14f29bf49712d382b [file] [log] [blame] [raw]
package li.cil.oc.api;
import cpw.mods.fml.common.event.FMLInterModComms;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import org.apache.commons.lang3.tuple.Pair;
/**
* This is a pure utility class to more comfortably register things that can
* only be registered using IMC.
* <p/>
* Use this if you have some kind of abstraction layer in place anyway, and can
* safely use the API without class not found exceptions and such, and don't
* want to put together the IMC messages manually.
* <p/>
* This also servers to document of all IMC messages OpenComputers handles.
* <p/>
* Feel free to copy these functions into your own code, just please don't
* copy this class while keeping the package name, to avoid conflicts if this
* class gets updated.
*/
@SuppressWarnings("unused")
public final class IMC {
/**
* Register a callback that is used as a filter for assembler templates.
* Any templates that require a base item that is rejected by <em>any</em>
* registered filter will be disabled. For example, if a filter rejects the
* computer case item stacks, robots can not be assembled.
* <p/>
* Signature of callbacks must be:
* <pre>
* boolean callback(ItemStack stack)
* </pre>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param callback the callback to register as a filtering method.
*/
public static void registerAssemblerFilter(final String callback) {
FMLInterModComms.sendMessage(MOD_ID, "registerAssemblerFilter", callback);
}
/**
* Register a new template for the assembler.
* <p/>
* Signature of callbacks must be:
* <pre>
* boolean select(ItemStack stack)
* Object[] validate(IInventory inventory)
* Object[] assemble(IInventory inventory)
* </pre>
* Values in the array returned by <tt>validate</tt> must be one of the following:
* <pre>
* // Valid or not.
* new Object[]{Boolean}
* // Valid or not, text for progess bar.
* new Object[]{Boolean, IChatComponent}
* // Valid or not, text for progess bar, warnings for start button tooltip (one per line).
* new Object[]{Boolean, IChatComponent, IChatComponent[]}
* </pre>
* Values in the array returned by <tt>assemble</tt> must be one of the following:
* <pre>
* // The assembled device.
* new Object[]{ItemStack}
* // The assembled device and energy cost (which also determines assembly duration).
* new Object[]{ItemStack, Number}
* </pre>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param name the name of the device created using the
* template. Optional, only used in logging.
* @param select callback used to determine if the template
* applies to a base item. For example, the robot
* template returns true from this if the passed
* item stack is a computer case.
* @param validate callback used to determine if the template
* configuration is valid. Once a template is
* valid assembly can be started, but not before.
* @param assemble callback used to apply a template and create a
* device from it.
* @param host the class of the device being assembled, i.e.
* the host class for the components being
* installed in the device. Used for filtering
* eligible components. See {@link #blacklistHost}.
* @param containerTiers the tiers of the container slots provided by the
* template. The length determines the number of
* containers. Maximum number is three.
* @param upgradeTiers the tiers of the upgrade slots provided by the
* template. The length determines the number of
* upgrades. Maximum number is nine.
* @param componentSlots the types and tiers of component slots provided by
* this template. May contain <tt>null</tt> entries
* to skip slots (slots are ordered top-to-bottom,
* left-to-right). For example, a robot template
* with only two card slots will pass <tt>null</tt>
* for the third component slot. Up to nine.
*/
public static void registerAssemblerTemplate(final String name, final String select, final String validate, final String assemble, final Class host, final int[] containerTiers, final int[] upgradeTiers, final Iterable<Pair<String, Integer>> componentSlots) {
final NBTTagCompound nbt = new NBTTagCompound();
if (name != null) {
nbt.setString("name", name);
}
nbt.setString("select", select);
nbt.setString("validate", validate);
nbt.setString("assemble", assemble);
if (host != null) {
nbt.setString("hostClass", host.getName());
}
final NBTTagList containersNbt = new NBTTagList();
if (containerTiers != null) {
for (int tier : containerTiers) {
final NBTTagCompound slotNbt = new NBTTagCompound();
slotNbt.setInteger("tier", tier);
containersNbt.appendTag(slotNbt);
}
}
if (containersNbt.tagCount() > 0) {
nbt.setTag("containerSlots", containersNbt);
}
final NBTTagList upgradesNbt = new NBTTagList();
if (upgradeTiers != null) {
for (int tier : upgradeTiers) {
final NBTTagCompound slotNbt = new NBTTagCompound();
slotNbt.setInteger("tier", tier);
upgradesNbt.appendTag(slotNbt);
}
}
if (upgradesNbt.tagCount() > 0) {
nbt.setTag("upgradeSlots", upgradesNbt);
}
final NBTTagList componentsNbt = new NBTTagList();
if (componentSlots != null) {
for (Pair<String, Integer> slot : componentSlots) {
if (slot == null) {
componentsNbt.appendTag(new NBTTagCompound());
} else {
final NBTTagCompound slotNbt = new NBTTagCompound();
slotNbt.setString("type", slot.getLeft());
slotNbt.setInteger("tier", slot.getRight());
componentsNbt.appendTag(slotNbt);
}
}
}
if (componentsNbt.tagCount() > 0) {
nbt.setTag("componentSlots", componentsNbt);
}
FMLInterModComms.sendMessage(MOD_ID, "registerAssemblerTemplate", nbt);
}
/**
* Register a new template for the disassembler.
* <p/>
* The <tt>disassemble</tt> callback gets passed the item stack to
* disassemble, and a list of inferred ingredients (based on crafting
* recipes). This is useful for not having to compute those yourself when
* you just want to add a number of items from an internal inventory to
* the output (e.g. for servers it's the components in the server).
* <p/>
* Signature of callbacks must be:
* <pre>
* boolean select(ItemStack stack)
* Object disassemble(ItemStack stack, ItemStack[] ingredients)
* </pre>
* <p/>
* Where the <code>Object</code> returned from the <code>disassemble</code>
* method must be one of the following:
* <ul>
* <li><code>ItemStack[]</code>: list of resulting items, subject to random failure.</li>
* <li><code>Object[]{ItemStack[],ItemStack[]}</code>: two lists of resulting items, the first being subject to
* random failure, the second being guaranteed drops (e.g. for item inventory contents).</li>
* </ul>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param name the name of the handler (e.g. name of the item
* being handled). Optional, only used in logging.
* @param select callback used to determine if the template
* applies to an item.
* @param disassemble callback used to apply a template and extract
* ingredients from an item.
*/
public static void registerDisassemblerTemplate(final String name, final String select, final String disassemble) {
final NBTTagCompound nbt = new NBTTagCompound();
if (name != null) {
nbt.setString("name", name);
}
nbt.setString("select", select);
nbt.setString("disassemble", disassemble);
FMLInterModComms.sendMessage(MOD_ID, "registerDisassemblerTemplate", nbt);
}
/**
* Register a callback for providing tool durability information.
* <p/>
* If your provider does not handle a tool/item, return <tt>Double.NaN</tt>
* to indicate that another provider should be queried. The first value
* that isn't <tt>NaN</tt> will be used as the durability.
* <p/>
* The returned value must be the <em>relative</em> durability of the tool,
* in a range of [0,1], with 0 being broken, 1 being new/fully repaired.
* <p/>
* Signature of callbacks must be:
* <pre>
* double callback(ItemStack stack)
* </pre>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param callback the callback to register as a durability provider.
*/
public static void registerToolDurabilityProvider(final String callback) {
FMLInterModComms.sendMessage(MOD_ID, "registerToolDurabilityProvider", callback);
}
/**
* Register a callback handling a wrench tool.
* <p/>
* These are used when determining whether an item is a wrench tool, when
* interacting with certain blocks while the player is holding such an item,
* for example to avoid rotating blocks when opening their GUI.
* <p/>
* The returned value must be <tt>true</tt> if the wrench was used/usable,
* <tt>false</tt> otherwise.
* <p/>
* Signature of callbacks must be:
* <pre>
* boolean callback(EntityPlayer player, BlockPos pos, boolean changeDurability)
* </pre>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param callback the callback to register as a wrench tool handler.
*/
public static void registerWrenchTool(final String callback) {
FMLInterModComms.sendMessage(MOD_ID, "registerWrenchTool", callback);
}
/**
* Register a callback for checking if an item is a wrench.
* <p/>
* This is used to determine whether certain item stacks are wrench items,
* which is used, for example, when "itemizing" a drone.
* <p/>
* The returned value must <tt>true</tt> if the item stack is a wrench,
* <tt>false</tt> otherwise.
* <p/>
* Signature of callbacks must be:
* <pre>
* boolean callback(ItemStack stack)
* </pre>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param callback the callback to register as a wrench tool tester.
*/
public static void registerWrenchToolCheck(final String callback) {
FMLInterModComms.sendMessage(MOD_ID, "registerWrenchToolCheck", callback);
}
/**
* Register a handler for items that can be charged.
* <p/>
* This is used by the charger to determine whether items can be charged
* by it (<tt>canCharge</tt>) and to actually charge them (<tt>charge</tt>).
* <p/>
* Note that OpenComputers comes with a few built-in handlers for third-
* party charged items, such as Redstone Flux and IndustrialCraft 2.
* <p/>
* Signature of callbacks must be:
* <pre>
* boolean canCharge(ItemStack stack)
* double charge(ItemStack stack, double amount, boolean simulate)
* </pre>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param name the name of the energy system/item type handled.
* @param canCharge the callback to register for checking chargeability.
* @param charge the callback to register for charging items.
*/
public static void registerItemCharge(final String name, final String canCharge, final String charge) {
final NBTTagCompound nbt = new NBTTagCompound();
nbt.setString("name", name);
nbt.setString("canCharge", canCharge);
nbt.setString("charge", charge);
FMLInterModComms.sendMessage(MOD_ID, "registerItemCharge", nbt);
}
/**
* Register a provider for ink usable in the 3D printer.
* <p/>
* Default providers in OpenComputers are one for the ink cartridges as
* well as one for arbitrary dyes (via the OreDictionary).
* <p/>
* Use this to make other items usable as ink in the 3D printer. Return a
* value larger than zero to indicate you handled the provided item stack,
* with the value being the amount of ink provided by the stack.
* <p/>
* Signature of callbacks must be:
* <pre>
* int callback(ItemStack stack)
* </pre>
* <p/>
* Callbacks must be declared as <tt>packagePath.className.methodName</tt>.
* For example: <tt>com.example.Integration.callbackMethod</tt>.
*
* @param callback the callback to register as an ink provider.
*/
public static void registerInkProvider(final String callback) {
FMLInterModComms.sendMessage(MOD_ID, "registerInkProvider", callback);
}
/**
* Blacklist a ComputerCraft peripheral from being wrapped by OpenComputers'
* built-in driver for ComputerCraft peripherals.
* <p/>
* Use this if you provide a driver for something that is a peripheral and
* wish to avoid conflicts in the registered callbacks, for example.
*
* @param peripheral the class of the peripheral to blacklist.
*/
public static void blacklistPeripheral(final Class peripheral) {
FMLInterModComms.sendMessage(MOD_ID, "blacklistPeripheral", peripheral.getName());
}
/**
* Blacklist an item for a specified host.
* <p/>
* This can be used to prevent certain components to be installed in select
* devices, via the devices class. For example, this is used to prevent
* components that would not be functional in certain devices to be
* installed in those devices, such as graphics cards in micro-controllers.
* <p/>
* The host class is the class of the environment the component would be
* installed in, e.g. {@link li.cil.oc.api.internal.Tablet}.
*
* @param name the name of the component being blacklisted.
* @param host the class of the host to blacklist the component for.
* @param stack the item stack representing the blacklisted component.
*/
public static void blacklistHost(final String name, final Class host, final ItemStack stack) {
final NBTTagCompound nbt = new NBTTagCompound();
nbt.setString("name", name);
nbt.setString("host", host.getName());
final NBTTagCompound stackNbt = new NBTTagCompound();
stack.writeToNBT(stackNbt);
nbt.setTag("item", stackNbt);
FMLInterModComms.sendMessage(MOD_ID, "blacklistHost", nbt);
}
/**
* Notifies OpenComputers that there is some 3rd-party power system present
* that adds integration on its side.
* <p/>
* This will suppress the "no power system found" message on start up, and
* avoid auto-disabling power use.
*/
public static void registerCustomPowerSystem() {
FMLInterModComms.sendMessage(MOD_ID, "registerCustomPowerSystem", "true");
}
/**
* Register a mapping of program name to loot disk.
* <p/>
* The table of mappings is made available to machines to allow displaying
* a message to the user telling her on which floppy disk to find the program
* they were trying to run.
* <p/>
* For Lua programs, this should be the program <em>name</em>, i.e. the file
* name without the <code>.lua</code> extension.
* <p/>
* The list of architectures is optional, if it is not specified this mapping
* will be made available to all architectures. It allows filtering since
* typically programs will be written for one specific architecture type, e.g.
* Lua programs will not (directly) work on a MIPS architecture. The name
* specified is the in the {@link li.cil.oc.api.machine.Architecture.Name}
* annotation of the architecture (also shown in the CPU tooltip).
* <p/>
* The architecture names for Lua are <code>Lua 5.2</code>, <code>Lua 5.3</code>
* and <code>LuaJ</code> for example.
*
* @param programName the name of the program.
* @param diskLabel the label of the disk the program is on.
* @param architectures the names of the architectures this entry applies to.
*/
public static void registerProgramDiskLabel(final String programName, final String diskLabel, final String... architectures) {
final NBTTagCompound nbt = new NBTTagCompound();
nbt.setString("program", programName);
nbt.setString("label", diskLabel);
if (architectures != null && architectures.length > 0) {
final NBTTagList architecturesNbt = new NBTTagList();
for (final String architecture : architectures) {
architecturesNbt.appendTag(new NBTTagString(architecture));
}
nbt.setTag("architectures", architecturesNbt);
}
FMLInterModComms.sendMessage(MOD_ID, "registerProgramDiskLabel", nbt);
}
// ----------------------------------------------------------------------- //
private static final String MOD_ID = "OpenComputers";
private IMC() {
}
}