Files
josh b853b3ae06 PlayerbotV2 module with core-hooks patches and full SQL migrations
Shipped patches:
  playerbotv2_core_hooks.patch    — stock TrinityCore master
  playerbotv2_core_hooks.thordekk.patch — ThordekkCore

SQL applied at module init by PlayerbotMigrationMgr:
  sql/playerbot_v2/0000_playerbot_shared_bootstrap.sql  — creates playerbot
    shared DB + tables (handcrafted_road, playerbots_names,
    playerbot_dungeon_routes, playerbot_nav_links,
    playerbot_v2_world_metadata)
  sql/playerbot_v2/0001..0016*.sql  — character DB tables

SQL auto-applied by TC DBUpdater:
  sql/updates/auth/master/
  sql/updates/characters/master/

Manual fallback:
  sql/playerbot/playerbot_bootstrap.sql

Static data (manual):
  src/modules/PlayerbotV2/sql/shared/
  src/modules/PlayerbotV2/sql/world/

Includes: Log.h, SpellAuras.h (PlayerbotAPI), Position.h (PlayerbotHooks)
2026-08-11 16:42:02 +10:00

75 lines
4.4 KiB
SQL

-- Migration: 0013_craft_orders
-- Date: 2026-06-15
-- Purpose: Bot-to-bot CRAFT-ORDER BOARD + escrow plumbing (#4B-2(a) part 1 of
-- docs/LIVING_SERVER_PLAN_20260614.md). Lets a requester bot post an
-- order for an item it can't make itself (escrowing the payment up
-- front by debiting its gold), a crafter bot that KNOWS the recipe
-- claim + fulfil it, and the escrow release/refund to settle the
-- transaction exactly once. This closes the profession economy loop:
-- gatherers feed reagents into the AH, crafters turn reagents into
-- finished goods on demand, and gold circulates between bots.
--
-- SECURITY (#4B-2 human-firewall): this is a CLOSED bot-to-bot system.
-- requester_low AND crafter_low are re-verified as CURRENT fleet bots
-- (Services::Registry()) at every state transition by CraftOrderBoard.
-- There is NO GM command / whisper / human entry point — a real player
-- can neither post, claim, fulfil, nor extract value from an order.
--
-- Columns:
-- id auto PK; the order id carried by snapshot + intent.
-- requester_low Player guid-low of the bot that posted the order
-- and whose gold was escrowed.
-- crafter_low Player guid-low of the bot that claimed it; NULL
-- while the order is still Open.
-- spell_id The craft recipe spell the order wants fulfilled.
-- item_entry The product item the recipe creates (item_template
-- entry), carried so the board / snapshot can describe
-- the order without re-resolving the spell.
-- quantity How many of the product the requester wants.
-- payment_copper The escrowed payment (copper). Debited from the
-- requester at PostOrder; paid to the crafter at
-- MarkDelivered OR refunded to the requester at
-- Fail/Cancel — EXACTLY ONCE, never both, never
-- neither. The `status` column is the single source
-- of truth that guards which of those two settlements
-- (if any) has already happened.
-- status 0=Open 1=Claimed 2=Delivered 3=Failed 4=Cancelled.
-- created_at When the order was posted (escrow taken).
-- claimed_at When a crafter claimed it; NULL while Open.
--
-- ESCROW INVARIANT (documented here + in CraftOrderBoard.h):
-- payment_copper is removed from the requester's gold EXACTLY ONCE,
-- at the Open transition (PostOrder). It then has exactly one of two
-- terminal fates:
-- * Delivered -> paid to the crafter (MarkDelivered), or
-- * Failed/Cancelled -> refunded to the requester (FailOrder).
-- A row may be settled only while transitioning OUT of a non-terminal
-- status (Open/Claimed) INTO a terminal one. Terminal rows
-- (Delivered/Failed/Cancelled) are never re-settled, so the gold can
-- never be double-released or double-refunded.
--
-- Reverts: yes (DROP TABLE).
--
-- Retention: finished rows (Delivered/Failed/Cancelled) are pruned by
-- CraftOrderBoard::Tick after a grace window; Open/Claimed rows are
-- reconciled into memory on load.
CREATE TABLE IF NOT EXISTS bot_craft_orders (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
requester_low BIGINT UNSIGNED NOT NULL,
crafter_low BIGINT UNSIGNED NULL DEFAULT NULL,
spell_id INT UNSIGNED NOT NULL DEFAULT 0,
item_entry INT UNSIGNED NOT NULL DEFAULT 0,
quantity INT UNSIGNED NOT NULL DEFAULT 1,
payment_copper BIGINT UNSIGNED NOT NULL DEFAULT 0,
status TINYINT UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
claimed_at DATETIME NULL DEFAULT NULL,
KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Record this migration as applied (mirrors the 0011/0012 record-version pattern).
INSERT INTO playerbot_v2_schema_version (version, sha256) VALUES
(13, REPEAT('0', 64))
ON DUPLICATE KEY UPDATE applied_at = CURRENT_TIMESTAMP;