Making MineFactory Reloaded aware of other mods
Since 1.1, MineFactory Reloaded has an extensibility API. Here's my explanation of how to use it.
This information is current for MFR version 1.3.x.
There's four interfaces you need: IFactoryPlantable, IFactoryHarvestable, IFactoryFertilizable, and IFactoryRanchable, which are located in net.minecraft.src.powercrystals.minefactoryreloaded.api (so is the HarvestType enum below). These are NOT implemented by your blocks/items; you need a new instance of them for each block or item you want to make MineFactory Reloaded aware of. There are default implementations of IFactoryPlantable, IFactoryHarvestable, and IFactoryRanchable provided.
Let's start with IFactoryPlantable. The planter needs to be aware of what thing it is going to plant, and what block it will become when it is planted. The interface is defined as:
public interface IFactoryPlantable
{
public int getSourceId();
public int getPlantedBlockId(World world, int x, int y, int z, ItemStack stack);
public int getPlantedBlockMetadata(World world, int x, int y, int z, ItemStack stack);
public boolean canBePlantedHere(World world, int x, int y, int z, ItemStack stack);
public void prePlant(World world, int x, int y, int z, ItemStack stack);
public void postPlant(World world, int x, int y, int z);
}
The methods mean the following:
- getSourceId: The ID of the "thing" inside the planter. For example, the sapling block ID or the wheat seeds item ID.
- getPlantedBlockId: The block ID to place on the ground.
- getPlantedBlockMetadata: The metadata value of the block that will be planted.
- canBePlantedHere: Return true if it is legal for the thing being planted to go here, and false if it should not be planted here. The XYZ coordinates are where the block will be placed.
- prePlant: If the planter should take additional steps prior to planting, do it here. For example, tilling fields for wheat.
- postPlant: If the planter should take additional steps after planting, do it here. No stock plants use this, but it is included for completeness.
The standard implementation is called "PlantableStandard". Its constructor takes a source ID and a block-to-be-placed ID; the metadata is copied straight from the source stack. It does nothing for prePlant or postPlant and uses the planted block's canPlaceBlockAt method (as well as making sure the destination block is air) for canBePlantedHere. If your block requires nothing special to be planted, you can just create a new instance of this class.
Next, IFactoryHarvestable. The harvester needs to know what block to look for, and what additional drops if any to produce when the block is harvested. In addition, it needs to know what "kind" of harvestable thing it is. The interface is defined as:
public interface IFactoryHarvestable
{
public int getSourceId();
public HarvestType getHarvestType();
public boolean canBeHarvested(World world, int x, int y, int z);
public boolean hasDifferentDrops();
public List<ItemStack> getDifferentDrops(World world, int x, int y, int z);
public void preHarvest(World world, int x, int y, int z);
public void postHarvest(World world, int x, int y, int z);
}
The methods mean the following:
- getSourceId: The block ID that is being harvested.
- getHarvestType: The "type" of harvestable block this is. See next section.
- canBeHarvested: For plants that should not be harvested until they have grown to a sufficient size, like wheat. Return true if the plant can be harvested and false if it should not be.
- hasDifferentDrops: True if this block will drop something that is different from Block.getBlockDropped()'s return value.
- getAdditionalDrops: A list of different items to drop. Will only be called if hasDifferentDrops returned true.
- preHarvest: If the harvester should take additional steps prior to harvesting, do it here. No stock plants use this, but it is included for completeness.
- postHarvest: If the harvester should take additional steps afterharvesting , do it here. "Stem" plants (pumpkin and melon) uses this to re-till the ground after they are harvested.
There are four types of harvestable items. This is defined in the HarvestType enum:
public enum HarvestType
{
Normal,
LeaveBottom,
Tree,
TreeLeaf
}
- Normal blocks are directly broken and harvested, with no special considerations. Wheat is a Normal harvest.
- LeaveBottom blocks grow upwards, and are replanted directly. As such, the bottommost block is left in place, and the harvester searches directly upwards for blocks to harvest. Cactus and sugarcane are LeaveBottom harvests.
- Tree blocks signal that a tree is attached to this point. If the harvester finds one of these on the ground, it will begin a tree search for something to harvest. Upper blocks will be harvested before lower blocks. Logs are a Tree harvest.
- TreeLeaf blocks are part of a tree, but are harvested before normal Tree blocks. When the harvester finds a tree, it will search upwards for all TreeLeaf blocks and then back downward for all Tree blocks. Use this if your block is a leaf, or something that hangs from leaves (like vines). Leaves and vines are a TreeLeaf harvest.
The standard implementation is HarvestableStandard. Its constructor requires the ID of the block being harvested, and the harvest type. It always returns true for canBeHarvested and always returns false for hasDifferentDrops, and does nothing in preHarvest/postHarvest. If your block requires nothing special to be harvested, you can just create a new instance of this class.
In 1.3, the default drop system is no longer idDropped/damageDropped/quantityDropped, but rather Forge's new Block.getBlockDropped method. If your block being harvested implements this correctly, then your work here will be greatly decreased.
Third, the fertilizer just needs to know what can be fertilized, what can be used as fertilizer, and how fertilizing actually works. The IFactoryFertilizable interface is defined as:
public interface IFactoryFertilizable
{
public int getFertilizableBlockId();
public boolean canFertilizeBlock(World world, int x, int y, int z, ItemStack fertilizer);
public boolean fertilize(World world, int x, int y, int z, ItemStack fertilizer);
}
The methods mean the following:
- getFertilizableBlockId: The block ID that will be fertilized.
- canFertilizeBlock: Return false if this block should not be fertilized (ie, wheat that is already fully grown, or the stack provided can't be used as a fertilizer for this plant).
- fertilize: Called to actually perform the fertilizing. The XYZ coordinates are of the block being fertilized.
There is no standard implementation for the fertilizer, because there is no standard way to fertilize things.
Finally, we have IFactoryRanchable, for the rancher. It needs to know what is being ranched, what to drop, and if the entity should be injured (and if so, by how much). It is defined as:
public interface IFactoryRanchable
{
public Class<?> getRanchableEntity();
public List<ItemStack> ranch(World world, EntityLiving entity, TileEntityRancher rancher);
public boolean getDamageRanchedEntity(World world, EntityLiving entity, List<ItemStack> drops);
public int getDamageAmount(World world, EntityLiving entity, List<ItemStack> drops);
}
The methods mean the following:
- getRanchableEntity: The class of your entity that will be ranched by this instance (the <?> is to deal with compiler warnings about generics). For example, to ranch a chicken, you'd use "return EntityChicken.class".
- ranch: This is where the magic happens. Return a list of drops from this ranching. The rancher instance is provided so that you can use its inventory (ie, for milking cows).
- getDamageRanchedEntity: True if the entity being ranched should be damaged. Based on a random number on all stock implementations. The drops returned by ranch above are provided here if you want it to depend on that instead.
- getDamageAmount: How much damage to do to the entity if the above function returns true. Again, the drops returned by ranch above are provided here if you want it to depend on that instead.
The standard implementation is called "Ranchabletandard". Its constructor takes, in order, the class to ranch, the stack to drop, the percent chance to injure the entity, the amount of damage to do, and the percent chance of dropping the item provided in the ItemStack earlier. This only supports a single drop from a ranch, so it is suggested that you create your own implementation for more complex entities. It uses the provided arguments to decide if it should drop the .. drop, and if it should damage the entity and by how much.
Note that the Rancher will ignore entities that are not a subclass of EntityLiving. If this is a problem for your mod, please contact me directly so we can discuss this.
Once you have created your instances, you need to call the following functions, located in mod_MineFactory:
public static void registerPlantable(IFactoryPlantable plantable)
public static void registerHarvestable(IFactoryHarvestable harvestable)
public static void registerFertilizable(IFactoryFertilizable fertilizable)
public static void registerFertilizerItem(int itemId)
public static void registerRanchable(IFactoryRanchable ranchable)
You simply pass your instance to the appropriate function and you are done. The registerFertilizerItem method takes an item ID and registers it as a valid ID that can be used to fertilize things; if this is not called, the fertilizer will ignore that item in its inventory. Only bonemeal ("itemDye") is registered by default.
Note that if more than one instance is provided for the same "source" ID, the latter instance will overwrite the former. Only one instance is supported per source ID.
If you are a modder and want a technical change or general help with this API, please feel free to post here. This specification was done from what I needed to make all the stock plants work and what I knew I needed for what mods I was aware of, but that can hardly be everything.