Give purchased items to characters
Expose the item catalog and apply item purchases through pack APIs
Item support has two parts. The catalog lets an admin find "Adena" or a Blessed
Scroll while creating content. Delivery turns a completed purchase into the
pack's normal addItem(...) call. Both are required.
Expose the item catalog
Register a fresh stream of the item templates already loaded by the game
server. Put this inside the Bridge.builder() call in
ForgeportIntegration.java; add the java.util.Arrays and java.util.Objects
imports if the file does not already have them:
.items(() -> Arrays.stream(ItemData.getInstance().getTemplates())
.filter(Objects::nonNull)
.map(item -> new GameItem(item.getItemId(), item.getName())))Your code maps pack objects to GameItem. Forgeport normalizes the admin's
query, ranks exact/prefix/substring matches, sorts the result, removes duplicate
ids, applies the limit, and serializes the response.
Deliver an item
If a player buys 10 Blessed Scrolls of Escape, the flow is:
Purchase completes
→ Forgeport calls .itemDelivery(...) with the selected character and item
→ your code validates the live player, account, and item template
→ your code returns a prepared Delivery
→ Forgeport records APPLYING
→ the pack's addItem(...) runs
→ Forgeport records APPLIED and reports the resultThe handler prepares the game change; it must not call addItem(...) before
returning Delivery.apply(...).
.itemDelivery((target, item) -> {
Player player = World.getInstance()
.getPlayer(target.requiredCharacterId());
if (player == null)
return Delivery.offline();
if (!player.getAccountName().equalsIgnoreCase(target.account()))
return Delivery.invalidTarget();
if (ItemData.getInstance().getTemplate(item.itemId()) == null)
return Delivery.invalidItem();
return Delivery.apply(() -> grantItems(player, item));
})grantItems(...) is your pack-specific helper that calls the normal item API.
Preserve enchant level and create non-stackable quantities one unit at a time;
the complete examples show the exact handling required by their revisions.
Never mutate before returning Delivery.apply
Forgeport must write the delivery journal before the actual game change. An early mutation can be repeated after a reconnect and bypasses the safety guarantees of the connector core.
Offline characters
The reference handlers return Delivery.offline(). Forgeport holds the
delivery, and the explicit EnterWorld hook resumes it:
Forgeport.playerOnline(player.getAccountName(), player.getObjectId());Call this only after the player is fully present in the live world.
Verify
- In Admin, search the item picker for
Adenaand confirm item57appears. - Run Connector check with a designated test character.
- Buy one low-value item with a test account.
- Confirm it appears once on the selected character.
- Repeat once with the character offline, then log in and confirm delivery resumes.
For the exact journal state machine, see L2J architecture.