#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}" if [[ -f "$ENV_FILE" ]]; then set -a # shellcheck disable=SC1090 source "$ENV_FILE" set +a fi IMPORT_MYTHICPLUS_SQL="${ACORE_IMPORT_MYTHICPLUS_SQL:-1}" IMPORT_STORE_SQL="${ACORE_IMPORT_STORE_SQL:-1}" usage() { cat <&2 exit 1 fi log "importing $(basename "$file_path") into ${database}" docker compose exec -T ac-database bash -lc \ "mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" \"$database\"" < "$file_path" } require_integer_flag() { local name="$1" local value="$2" if ! [[ "$value" =~ ^[01]$ ]]; then printf '%s must be 0 or 1, got: %s\n' "$name" "$value" >&2 exit 1 fi } maybe_import_table() { local database="$1" local table_name="$2" local file_path="$3" if table_exists "$database" "$table_name"; then log "table ${database}.${table_name} already exists, skipping" return 0 fi import_sql_file "$database" "$file_path" } import_mythicplus_sql() { if [[ "$IMPORT_MYTHICPLUS_SQL" == "0" ]]; then log "MythicPlus SQL import disabled, skipped" return 0 fi if [[ ! -d "$ROOT_DIR/sql/Mythic+" ]]; then log "sql/Mythic+ directory not found, skipped" return 0 fi maybe_import_table "acore_characters" "character_mythic_history" \ "$ROOT_DIR/sql/Mythic+/characters/character_mythic_history.sql" maybe_import_table "acore_characters" "character_mythic_keys" \ "$ROOT_DIR/sql/Mythic+/characters/character_mythic_keys.sql" maybe_import_table "acore_characters" "character_mythic_rating" \ "$ROOT_DIR/sql/Mythic+/characters/character_mythic_rating.sql" maybe_import_table "acore_characters" "character_mythic_vault" \ "$ROOT_DIR/sql/Mythic+/characters/character_mythic_vault.sql" maybe_import_table "acore_characters" "character_mythic_weekly_affixes" \ "$ROOT_DIR/sql/Mythic+/characters/character_mythic_weekly_affixes.sql" maybe_import_table "acore_world" "world_mythic_loot" \ "$ROOT_DIR/sql/Mythic+/world/world_mythic_loot.sql" maybe_import_table "acore_world" "world_vault_loot" \ "$ROOT_DIR/sql/Mythic+/world/world_vault_loot.sql" if [[ "$(mysql_query "acore_world" " SELECT CASE WHEN EXISTS (SELECT 1 FROM creature_template WHERE entry = 900001) AND EXISTS (SELECT 1 FROM item_template WHERE entry = 900100) AND EXISTS (SELECT 1 FROM gameobject_template WHERE entry = 900000) AND EXISTS (SELECT 1 FROM creature WHERE id1 = 900001 OR id2 = 900001 OR id3 = 900001) AND EXISTS (SELECT 1 FROM gameobject WHERE id = 900000) THEN 1 ELSE 0 END; ")" == "0" ]]; then log "repairing MythicPlus world bootstrap entries" mysql_exec "acore_world" " DELETE FROM creature WHERE id1 = 900001 OR id2 = 900001 OR id3 = 900001; DELETE FROM gameobject WHERE id = 900000; DELETE FROM creature_template_locale WHERE entry = 900001; DELETE FROM item_template_locale WHERE ID = 900100; DELETE FROM creature_template_model WHERE CreatureID = 900001; DELETE FROM creature_template WHERE entry = 900001; DELETE FROM item_template WHERE entry = 900100; DELETE FROM gameobject_template WHERE entry = 900000; " import_sql_file "acore_world" "$ROOT_DIR/sql/Mythic+/world/creature_and_keystones.sql" else log "MythicPlus creature bootstrap already exists, skipping" fi } import_store_sql() { local store_sql_file="$ROOT_DIR/sql/Store.sql" local temp_sql="" if [[ "$IMPORT_STORE_SQL" == "0" ]]; then log "Store SQL import disabled, skipped" return 0 fi if [[ ! -d "$ROOT_DIR/lua_scripts/Store_System" ]]; then log "lua_scripts/Store_System directory not found, skipped" return 0 fi if [[ ! -f "$store_sql_file" ]]; then log "sql/Store.sql not found, skipped" return 0 fi if ! database_exists "store"; then log "creating database store" mysql_exec "" "CREATE DATABASE IF NOT EXISTS \`store\` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" fi temp_sql="$(mktemp)" { printf 'CREATE DATABASE IF NOT EXISTS `store` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;\n' printf 'USE `store`;\n' awk ' BEGIN { skip = 0 } skip { if ($0 ~ /;[[:space:]]*$/) { skip = 0 } next } $0 ~ /^INSERT INTO `store_logs` / { skip = 1 next } { sub(/^INSERT INTO /, "INSERT IGNORE INTO ") print } ' "$store_sql_file" } > "$temp_sql" log "bootstrapping store database" mysql_exec "" "$(cat "$temp_sql")" rm -f "$temp_sql" } import_aoe_loot_sql() { local aoe_loot_sql_file="$ROOT_DIR/modules/mod-aoe-loot/data/sql/db-world/base/aoe_loot_module_string.sql" if [[ ! -f "$aoe_loot_sql_file" ]]; then log "mod-aoe-loot module string SQL not found, skipped" return 0 fi if [[ "$(mysql_query "acore_world" "SELECT COUNT(*) FROM module_string WHERE module = 'mod-aoe-loot';")" != "0" ]] && \ [[ "$(mysql_query "acore_world" "SELECT COUNT(*) FROM module_string_locale WHERE module = 'mod-aoe-loot';")" != "0" ]]; then log "mod-aoe-loot module strings already exist, skipping" return 0 fi import_sql_file "acore_world" "$aoe_loot_sql_file" } import_taxi_builder_sql() { # Source-of-truth tables for the Taxi Route Builder. The migration also # lives in data/sql/updates/pending_db_world/ for AzerothCore DBUpdater, # but we apply it eagerly here so deploy flows that don't rely on the # worldserver-side updater still bootstrap correctly. local taxi_builder_sql_file="$ROOT_DIR/data/sql/updates/pending_db_world/rev_1778279831177904414.sql" if [[ ! -f "$taxi_builder_sql_file" ]]; then log "taxi-builder migration not found, skipped" return 0 fi if table_exists "acore_world" "custom_taxi_nodes" \ && table_exists "acore_world" "custom_taxi_paths" \ && table_exists "acore_world" "custom_taxi_path_nodes"; then log "taxi-builder tables already exist, skipping" return 0 fi import_sql_file "acore_world" "$taxi_builder_sql_file" } if (($# > 0)); then case "$1" in -h|--help) usage exit 0 ;; *) printf 'Unknown option: %s\n\n' "$1" >&2 usage >&2 exit 1 ;; esac fi require_integer_flag "ACORE_IMPORT_MYTHICPLUS_SQL" "$IMPORT_MYTHICPLUS_SQL" require_integer_flag "ACORE_IMPORT_STORE_SQL" "$IMPORT_STORE_SQL" cd "$ROOT_DIR" if ! docker compose ps --status running --services | grep -qx 'ac-database'; then printf 'ac-database is not running. Start the database first.\n' >&2 exit 1 fi import_mythicplus_sql import_aoe_loot_sql import_taxi_builder_sql import_store_sql log "custom SQL bootstrap completed"