Skip to content
Uristqwerty edited this page Jun 18, 2017 · 4 revisions

Interacting with CraftGuide

CraftGuide's API is built largely around polling objects for information. Those objects must first be registered with CraftGuide (typically during game startup). The most convenient way to do so is to create an instance of an object extending CraftGuideAPIObject, which automatically registers itself during construction.

Typical usage:

class DoohickeyRecipes extends CraftGuideAPIObject implements RecipeProvider
{
	// ...
}

// In the @Mod class
@EventHandler
public void init(FMLInitializationEvent event)
{
	if(Loader.isModLoaded("craftguide"))
	{
		try
		{
			// Use reflection here so that the JVM doesn't try (and fail) to load classes
			// that depend on CraftGuide when it isn't present.
			Class.forName("mymod.integration.craftguide.DoohickeyRecipes").newInstance();
			Class.forName("mymod.integration.craftguide.AnotherThing").newInstance();
		}
		catch (ReflectiveOperationException e)
		{
			e.printStackTrace();
		}
	}
}

Adding recipes to display

When CraftGuide builds its list of recipes to display, it first polls every api object that implements RecipeProvider. The RecipeProvider can then add recipes through the RecipeGenerator instance, implemented by CraftGuide, it is given.

The new-and-improved, up-and-coming new way

Experimental in late Minecraft 1.7.10 versions but hopefully stable past that, there is a new convenience layer that greatly simplifies layout.

Functionally, it's very similar to the old manually-positioned way, described below, but everything is automatically aligned into columns so you don't need to fiddle with pixel coordinates. On top of that, it has convenience methods for dealing with both shaped and shapeless grids, so you just declare the grid's dimensions when creating the template, then when adding recipes you can just pass a List<> or array[]. For shapeless grids, you don't even have to match the length of the grid!

Example:

class DoohickeyRecipes extends CraftGuideAPIObject implements RecipeProvider
{
	@Override
	public void generateRecipes(RecipeGenerator generator)
	{
		ItemStack doohickeyMachine = MyAPI.getBlockItem("doohickey");
		
		ConstructedRecipeTemplate template = generator.buildTemplate(doohickeyMachine)
				.item().nextColumn(1)
				.machineItem().nextColumn(1)
				.outputItem().finishTemplate();
		
		for(DoohickeyRecipe recipe: MyAPI.getDoohickeyRecipes())
		{
			template.buildRecipe()
					.item(recipe.getInput())
					.item(doohickeyMachine)
					.item(recipe.getOutput())
					.addRecipe(generator);
		}
	}
}

The manually-positioned way

Fairly easy to demonstrate, this method of providing recipes can be summarized in steps:

  • Layout the recipe, by creating an array of Slot objects.
  • Pass this array to the RecipeGenerator, plus an ItemStack to represent the type of recipe, getting back a RecipeTemplate
  • (Optional) Change the width and height of the template
  • For each recipe, construct an Object[] containing the data used by the Slot[] array.

Example:

class DoohickeyRecipes extends CraftGuideAPIObject implements RecipeProvider
{
	@Override
	public void generateRecipes(RecipeGenerator generator)
	{
		ItemStack doohickeyMachine = MyAPI.getBlockItem("doohickey");
		
		RecipeTemplate template = generator.createRecipeTemplate(
				new Slot[]{
						new ItemSlot(12, 21, 16, 16, true).drawOwnBackground(true),
						new ItemSlot(50, 21, 16, 16, true).setSlotType(SlotType.OUTPUT_SLOT).drawOwnBackground(true),
						new ItemSlot(31, 21, 16, 16, true).setSlotType(SlotType.MACHINE_SLOT).drawOwnBackground(false),
				}, doohickeyMachine);
		
		for(DoohickeyRecipe recipe: MyAPI.getDoohickeyRecipes())
		{
			recipeGenerator.addRecipe(template,
					new Object[] {
							recipe.getInput(),
							recipe.getOutput(),
							doohickeyMachine
					});
		}
	}
}

The do-it-yourself way

At a lower level, you can create your own objects that implement CraftGuideRecipe, then add them through RecipeGenerator's

public void addRecipe(CraftGuideRecipe recipe, ItemStack craftingType);

method. This is more powerful, as the above-described Slot-based method is just a layer of abstraction implemented using this lower-level API, but it is also more work as it requires implementing any rendering and user interaction necessary.

Filtering out recipes that shouldn't be displayed

API object implementing either BasicRecipeFilter or RecipeFilter are given the opportunity to remove recipes once all of the RecipeProviders have added recipes. BasicRecipeFilter only answers true or false as to whether to keep each recipe, while RecipeFilter has full mutable access to the recipe list for each type of recipe, and is able to insert, delete, and re-order contents.

Example:

// Hides recipes that use diamonds as input
class DiamondFilter extends CraftGuideAPIObject implements BasicRecipeFilter
{
	@Override
	public boolean shouldKeepRecipe(CraftGuideRecipe recipe, ItemStack recipeType)
	{
		ItemStack diamond = new ItemStack(Items.diamond);
		
		if(recipe instanceof CraftGuideRecipeExtra1)
		{
			return !((CraftGuideRecipeExtra1)recipe).containsItem(diamond, SlotType.INPUT_SLOT);
		}
		else
		{
			return !recipe.containsItem(diamond);
		}
	}
}

Minor tasks

Adding information to item tooltips displayed within CraftGuide

When CraftGuide gets the mouseover text of an ItemStack, it also polls objects implementing StackInfoSource, each of which may either return a String containing a line of text to append to the tooltip, or null. These objects are registered using StackInfo.addSource(object), rather than, or in addition to, .

This is typically used for displaying the energy value of an item, or other information associated with an ItemStack and not a recipe.

Example:

class DiamondTooltip implements StackInfoSource
{
	public DiamondTooltip()
	{
		StackInfo.addSource(this);
	}

	@Override
	public String getInfo(ItemStack stack)
	{
		if(stack.getItem() == Items.diamond)
		{
			return "Ooh, shiny!";
		}
		
		return null;
	}
}

Reloading the list of displayed recipes

CraftGuide will reload its list of recipes when either of the following methods are invoked:

uristqwerty.CraftGuide.ReflectionAPI.reloadRecipes()
uristqwerty.CraftGuide.api.Util.instance.reloadRecipes()