When you move from a World Boss (where "close enough" is fine) to an Economy (where a single duplicate item can destroy the game), you must switch from **Eventual Consistency** to **Strong Consistency**. In distributed systems, this is the "hard mode" of engineering. To handle this, the DSL moves away from the Delta-Sync model and implements **Two-Phase Commit (2PC)** and **Distributed Locking with Deadlock Avoidance**. Here is how the DSL handles absolute consistency for P2P trades and Auction Houses. --- ### 1. The P2P Trade: The "Prepare-Commit" Pattern A cross-shard trade is dangerous because if the server crashes *after* taking the item from Player A but *before* giving it to Player B, the item vanishes. To prevent this, the DSL uses a **Two-Phase Commit (2PC)** logic wrapped in a **Saga**. ```python # ============================================================================== # SCENARIO: Cross-Shard Player-to-Player Trade # STRATEGY: Two-Phase Commit (Reserve -> Commit) + Compensation # ============================================================================== Module CrossShardTrade { # 1. The Setup: Lock both players to prevent them from trading with others # We lock by ID in a fixed order (e.g., lower ID first) to avoid Deadlocks Lock (SortedIds($player_a, $player_b)) { # PHASE 1: PREPARE (The "Reservation" Phase) # We don't move the items yet; we just "freeze" them. Trade.ReserveItem($player_a, $item_id) -> ReserveA.Success Trade.ReserveCurrency($player_b, $price) -> ReserveB.Success # Check if both reservations succeeded [ReserveA.Success, ReserveB.Success] J-> Trade.Commit # If either fails (e.g., Player B spent their money), trigger the Undo [ReserveA.Fail, ReserveB.Fail] -> Trade.Abort } # PHASE 2: COMMIT (The "Atomic" Phase) Trade.Commit /execute { # These two operations are wrapped in a single distributed transaction # If one fails here, the system triggers a critical recovery saga Saga.AtomicTransfer { RemoveItem($player_a, $item_id), AddItem($player_b, $item_id), RemoveCurrency($player_b, $price), AddCurrency($player_a, $price) } -> Trade.Complete } # THE UNDO: ABORT (Compensation) Trade.Abort /execute { # Unfreeze the items/currency Saga.UndoReservation($player_a, $item_id), Saga.UndoReservation($player_b, $price) -> Trade.Failed } } ``` --- ### 2. The Global Auction House: The "Escrow" Pattern An Auction House is even more complex because it's an **Asynchronous Trade** (Seller is not present). To handle this, the DSL implements an **Escrow (Third-Party Vault)**. Instead of moving money directly from Buyer to Seller, the system uses a **Vault** as the source of truth. ```python # ============================================================================== # SCENARIO: Global Auction House # STRATEGY: Escrow Vault + Atomic Swap # ============================================================================== Module AuctionHouse { # 1. Listing the Item # The item is REMOVED from the player and placed in the VAULT. # This prevents the player from trading the item while it's for sale. Auction.ListItem /execute { Lock ($seller_id) { EXT:Vault.DepositItem { item: $item_id, owner: $seller_id } } } # 2. Placing a Bid (The Atomic Swap) # We must ensure the previous high bidder is refunded instantly # and the new bidder's funds are locked. Auction.PlaceBid /execute { Lock ($item_id) { # Lock the item to prevent double-bidding # A. Reserve new bid funds Vault.ReserveFunds($bidder_id, $new_price) -> Bid.Reserve # B. Refund previous bidder if ($previous_bidder) { Vault.ReleaseFunds($previous_bidder, $old_price) } # C. Update the high bidder state GlobalAuctionState.Update { high_bidder: $bidder_id, current_price: $new_price } } } # 3. Closing the Auction (The Settlement) Auction.Settle /execute { Lock ($item_id) { # Atomic transfer from Vault -> Buyer and Funds -> Seller Saga.AtomicSettle { Vault.TransferItem($buyer_id), Vault.TransferFunds($seller_id) } } } } ``` --- ### 3. Solving the "Distributed Nightmare" Problems #### A. Deadlock Avoidance (The "Dining Philosophers" Problem) In the P2P trade, if Player A locks Player A and waits for Player B, while Player B locks Player B and waits for Player A, the system freezes. * **The DSL Solution:** `SortedIds($player_a, $player_b)`. * By always locking the IDs in numerical order (e.g., always lock ID 10 before ID 50), the system ensures that circular dependencies are impossible. #### B. The "Atomic" Guarantee (The Vault) To avoid "Item Duplication" (the most feared bug in game dev), the DSL relies on **Idempotent Transactions**. * Every single move of an item is assigned a **Unique Transaction ID (UUID)**. * If the server crashes and restarts the `Saga.AtomicTransfer`, the Vault checks the UUID. If it sees the item was already moved, it ignores the second request rather than moving the item again. #### C. Performance vs. Consistency Because these workflows use **Locks** and **Strong Consistency**, they are significantly slower than the World Boss's Delta-Sync. * **The DSL Strategy:** The engine routes these to a **High-Consistency Partition**. * While the "Combat Engine" uses fast, eventual consistency, the "Trade Engine" uses a dedicated, highly-consistent database (like **CockroachDB** or **FoundationDB**) that supports distributed ACID transactions. ### Summary: Delta-Sync vs. Strong Consistency | Feature | World Boss (Delta-Sync) | Trade/Auction (Strong Consistency) | | :--- | :--- | :--- | | **Priority** | Throughput & Low Latency | Accuracy & Integrity | | **Core Logic** | `HP -= Delta` | `Lock` > `Reserve` >`Commit` | | **Conflict Handling**| Commutative (Order doesn't matter) | Sequential (Order is everything) | | **Error Recovery** | Eventual Correction (Saga) | Atomic Rollback (Undo) | | **Latency** | Extremely Low (Buffered) | Moderate (Lock-wait) | | **Risk** | Small inaccuracies (Acceptable) | Item Duplication (Catastrophic) |