Metin2

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.

portal.toml
[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
)
"""
  • login makes the award available to any character on the account.
  • mall = 1 sends it to the Item Shop storage tab.
  • why = @commandId gives the queue its replay key.
  • WHERE NOT EXISTS makes 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:

portal.toml
[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

  1. Buy one low-value item and confirm the item_award row is created once.
  2. Claim it from Item Shop storage and confirm the order settles.
  3. Replay the same command id in a controlled test and confirm no duplicate row.
  4. Credit a small currency amount and compare the account value before/after.
  5. Confirm restarting the connector does not apply the same credit again.

On this page