Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

A mod's own capability

A mod can define a capability of its own, as Mekanism defines chemicals: a resource type and a key, published from its root crate (Dependencies between trait mods) for other mods to use.

#![allow(unused)]
fn main() {
// The chemistry mod's root crate
#[derive(Clone, PartialEq)]
pub struct Chemical(pub String);
pub const CHEMICALS: CapabilityKey<dyn ResourceHandler<Chemical>> = CapabilityKey::new("chem_api:chemical");
}

A mod that names it under [dependencies] builds against the same Chemical and CHEMICALS, so its providers, r.block_entity_capability(&chem_api::CHEMICALS, &vat, …) (where vat is a declared type key or r.block_entity_type_key("chem_pipe:vat")), answer the same capability, and level.capability(host, &chem_api::CHEMICALS, pos, side) finds either mod's handler. move_resources moves a chemical as it moves items, in the caller's transaction. The game has no answer of its own for a mod's key, so only the mods' providers do, and a lookup with none registered costs one table check. A handler that keeps its amount in its block entity's saved data (BlockEntityRef::merge_data) is covered by the game's journal, so an aborted transaction puts it back. ItemCapabilityKey::new and EntityCapabilityKey::new define item and entity capabilities the same way.

A key is known by its name, which must be namespaced (chem_api:chemical), and a name has one handler type. Two mods that each declare their own Chemical under one name, rather than sharing the defining mod's, would never see each other's handlers. So the game refuses that at startup, naming both mods and both types, and it refuses a key whose name has no namespace. Both checks run once, when the mods register.