Deliver items and currency
Use Metin2 item_award and replay-safe account credits
Item delivery uses the game's native gift-box queue. Currency delivery updates the account row in real time. Both paths are account-scoped, so the player does not choose a character and delivery is not held for login.
Give purchased items
If a player buys an item, Forgeport inserts one row into player.item_award.
The game core polls that table on its own cycle, moves the item to Item Shop
storage, and stamps taken_time when the player claims it.
[delivery.item]
window = "both"
sql = """
INSERT INTO {playerDb}.item_award (login, vnum, count, mall, why, given_time)
SELECT @account, @itemId, @count, 1, @commandId, NOW() FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM {playerDb}.item_award WHERE why = @commandId
)
"""loginmakes the award available to any character on the account.mall = 1sends it to the Item Shop storage tab.why = @commandIdgives the queue its replay key.WHERE NOT EXISTSmakes a repeated command insert nothing.given_time = NOW()avoids invalid zero-date defaults.
The connector reports the purchase queued, then polls the row every
[queue].pollSeconds (30 by default). taken_time means the player claimed it.
After expiryDays (30 by default), an unclaimed award is deleted, the delivery
closes as expired, and the player's coins are returned.
Test the gift box on your base
Keep window = "both" only if item_award is claimable online and offline on
this base. A successful insert does not prove that the game core consumes it.
Credit Dragon Coins or Dragon Marks
account.cash and account.mileage are real-time account credits:
[delivery.cash]
sql = """
UPDATE {accountDb}.account
SET cash = cash + @amount
WHERE login = @account
"""
[delivery.mileage]
sql = """
UPDATE {accountDb}.account
SET mileage = mileage + @amount
WHERE login = @account
"""The connector creates portal_grant_journal and commits the journal row and
credit in one transaction. A replay credits nothing twice.
Keep currency SQL as a plain credit
Do not add a second idempotency guard to these updates. A zero-row update means
no matching account and is correctly refused as ACCOUNT_NOT_FOUND.
Configuring either currency enables the shared currency-delivery capability. Keep both sections unless the base has removed one column; otherwise a product using the missing currency can reach delivery and fail.
Verify
- Buy one low-value item and confirm the
item_awardrow is created once. - Claim it from Item Shop storage and confirm the order settles.
- Replay the same command id in a controlled test and confirm no duplicate row.
- Credit a small currency amount and compare the account value before/after.
- Confirm restarting the connector does not apply the same credit again.