Skip to content

Public API ​

Compile-time dependency ​

xml
<repositories><repository><id>jiuwu-releases</id><url>https://repo.crypticlib.com/repository/maven-public/</url></repository></repositories>
<dependency><groupId>emaki.jiuwu.craft</groupId><artifactId>emaki-forge-api</artifactId><version>4.8.6</version><scope>provided</scope></dependency>
kotlin
repositories { maven("https://repo.crypticlib.com/repository/maven-public/") }
dependencies { compileOnly("emaki.jiuwu.craft:emaki-forge-api:4.8.6") }

Compile only — never install, shade, or relocate this jar

Do not drop the API jar into plugins/, and do not bundle, shade, or relocate it. EmakiForge-4.8.8.jar already embeds these un-relocated API/event classes; a duplicate ClassLoader copy breaks Bukkit events and the static bridge

Use EmakiForgeApi.status().usable(). catalog(), operations(), and the currently empty experimental extensions() accessor are non-null; when EmakiForge is absent they return empty queries, unavailable results, or an empty extension layer. install, uninstall, and Bridge belong to the runtime lifecycle and must not be called, implemented, or proxied by third parties

Catalog ​

recipes() returns loaded recipes in recipe-book order (empty when unavailable) and recipe(String) looks up an id normalised with Locale.ROOT. recipes(), recipe(String), materialById(String), and materialByItem(ItemStack) are any-thread reads of the immutable loaded definitions; live item stacks must respect their holder's owner thread. Player-scoped matchRecipe, validate, experimental previewResult, and experimental mastery require the player's owner thread. validate represents a rule refusal as Success<ForgeValidation> with allowed()==false and carries reasonKey() plus placeholders() for rendering the rejection. accepting() reports whether new attempts are accepted

Experimental mastery(Player, String) reads the player's persisted successful craft count for that recipe; when the current session data is not loaded yet the result is UNAVAILABLE, never a fabricated zero

Programmatic forging ​

operations().forgeAsync(player, recipeId, inputs) is experimental and accepts calls from any thread. It uses the real preparation, validation, actions, quality, delivery, history, and event path, dispatching Bukkit work to the player's owner thread. Its future carries EmakiResult<ForgeOutcome>; cancelling the future cannot undo an attempt that crossed the delivery commit boundary

ForgeInputs is detached escrow with the fields targetItem, blueprints, requiredMaterials, and optionalMaterials; every stack is cloned on construction and on access, and ForgeInputs.empty() / ForgeInputs.ofRequired(map) are convenience constructors. EmakiForge never scans or removes stacks from arbitrary inventory slots, so the caller must reserve/commit/release the physical inventory items itself. ForgeOutcome exists only after a successful committed delivery and contains the canonical recipe id, a cloned result item, the quality id, and the multiplier. Chance failure, validation rejection, event cancellation, runtime unavailability, and execution errors are outer EmakiResult failures, not outcomes

Other operations are owner-thread GUI/book access, viewingRecipeBook, refreshItem, and refreshPlayer; extensions() invents no extra pipeline

  • openForgeGui(Player[, recipeId]), openRecipeBook(Player, page), viewingRecipeBook(Player): player owner thread. page is zero-based and a negative value is treated as 0; viewingRecipeBook uses EmakiResult<Boolean> so "not open" is not collapsed into "unavailable"
  • refreshItem(ItemStack): holder owner thread; returns Partial for items that carry no EmakiForge data
  • refreshPlayer(Player): refreshes inventory, armour, off hand, and cursor; player owner thread

Results ​

Use Success, Partial, Failure, and optionalValue(). Failure kinds: UNAVAILABLE, NOT_FOUND, INVALID_INPUT, REJECTED, CANCELLED, TARGET_OFFLINE, WRONG_THREAD, INTERNAL_ERROR