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-storage-api</artifactId><version>1.1.3</version><scope>provided</scope></dependency>
kotlin
repositories { maven("https://repo.crypticlib.com/repository/maven-public/") }
dependencies { compileOnly("emaki.jiuwu.craft:emaki-storage-api:1.1.3") }

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

EmakiStorage embeds the un-relocated API. A bundled copy breaks event and static bridge identity

Facade ​

Availability is determined by EmakiStorageApi.status().usable(). The only business layer that is non-null is operations(); install, uninstall and Bridge belong to the runtime only and must not be relied on

All asynchronous methods ​

Method contract: except for openGui, every public read/write method carries the Async suffix and returns CompletableFuture<EmakiResult<...>>:

MethodSemantics
readSnapshotAsync(UUID)Reads a detached StorageSnapshot, loading from the file lane when it is not cached
depositAsync(UUID,ItemStack,long)Adds items to storage without taking them from the caller's inventory
withdrawAsync(UUID,ItemStack,long)Debits storage and hands the items to the online owner
countOfAsync(UUID,ItemStack)Returns the real count, including a legitimate zero
countAllAsync(UUID,Collection<ItemStack>)Counts several templates in one pass, returning Map<ItemStack,Long>. A template absent from storage maps to 0L rather than being missing. Available for offline players
applyBatchAsync(UUID,StorageBatchRequest)Atomic signed increments that never route through the player's inventory. allOrNothing is declared inside StorageBatchRequest, not as a separate parameter; the payload is StorageBatchResult. Exceeding behavior.batch_max_ops returns INVALID_INPUT with batch_too_large and applies nothing
reserveAsync(UUID,StorageBatchRequest,Duration)Holds only the withdrawal side of the request; the payload is a ReservationHandle. Deposit ops in the request are ignored, because a reservation holds stock back rather than pre-booking capacity. A non-positive ttl is rejected. Reservations survive a restart and are released on load once ttl has elapsed
commitAsync(ReservationHandle)Applies a reserved batch; the payload is StorageBatchResult. It takes the handle only, with no UUID, and re-runs the deposit-side pre-checks
releaseAsync(ReservationHandle)Drops a hold; the payload is Unit. It takes the handle only. Idempotent: an unknown or already-released handle returns NOT_FOUND rather than failing loudly
grantSlotsAsync(UUID,int)Adjusts the admin-managed granted-slot pool
setStackLimitAsync(UUID,long)Sets the player-level default per-slot ceiling; 0 restores config inheritance
setSlotStackLimitAsync(UUID,int,long)Sets one logical entry's ceiling; 0 restores player-default inheritance

Thread contract: these futures may be submitted from any thread and the runtime does the real work on the file lane or the player's owner thread, but a future callback is not guaranteed to run on the Bukkit owner thread. Re-dispatch before touching players, inventories or the world

Synchronous method requirement: openGui(Player) is the only synchronous operation. It requires the supplied player's owner thread and never schedules a later open; a call from any other thread returns WRONG_THREAD

Return model: StorageSnapshot is an immutable detached snapshot. StorageAmount reports requested and applied amounts plus remaining() and complete(); an under-capacity deposit can return a Partial carrying the amount actually applied

Event boundary ​

Trigger rules: the asynchronous API fires the corresponding synchronous events on its actual transaction path; never assume every underlying edit has an event just because two methods look similar. In particular, the current implementation path for a direct async withdrawal is whatever the runtime transaction service does, and the events page lists the exact coverage

Batch and reservation boundary: exactly one StorageBatchEvent fires for a whole batch; per-op deposit and withdraw events are deliberately not fired inside a batch. Reserved units stay visible through StorageEntrySnapshot#reservedAmount() but are excluded from what applyBatchAsync may take, so the same units cannot be promised twice

Source is fixed: every public API method records its source as api and the caller cannot choose one; the gui, command, action and auto_pickup sources are only produced by the plugin's own entry points

Result semantics ​

Result contract: use Success, Partial, Failure, and optionalValue(). Failure kinds are exactly UNAVAILABLE, NOT_FOUND, INVALID_INPUT, REJECTED, CANCELLED, TARGET_OFFLINE, WRONG_THREAD, INTERNAL_ERROR. Ordinary business failures are expressed by the result rather than by a failed future