312 lines
9.7 KiB
Bash
312 lines
9.7 KiB
Bash
#!/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}"
|
|
IMPORT_ENCOUNTER_JOURNAL_SQL="${ACORE_IMPORT_ENCOUNTER_JOURNAL_SQL:-1}"
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $(basename "$0")
|
|
|
|
Imports required custom SQL that lives outside the normal AzerothCore module paths.
|
|
Currently this bootstraps the MythicPlus and Store Lua packages, plus module strings
|
|
that are not covered by the normal module SQL import path in this deployment.
|
|
EOF
|
|
}
|
|
|
|
log() {
|
|
printf '[import-custom-sql] %s\n' "$*"
|
|
}
|
|
|
|
mysql_query() {
|
|
local database="$1"
|
|
local sql="$2"
|
|
|
|
docker compose exec -T ac-database bash -lc \
|
|
"mysql -N -s -uroot -p\"\$MYSQL_ROOT_PASSWORD\" \"$database\"" <<<"$sql"
|
|
}
|
|
|
|
mysql_exec() {
|
|
local database="${1:-}"
|
|
local sql="$2"
|
|
|
|
if [[ -n "$database" ]]; then
|
|
docker compose exec -T ac-database bash -lc \
|
|
"mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" \"$database\"" <<<"$sql"
|
|
else
|
|
docker compose exec -T ac-database bash -lc \
|
|
"mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\"" <<<"$sql"
|
|
fi
|
|
}
|
|
|
|
table_exists() {
|
|
local database="$1"
|
|
local table_name="$2"
|
|
local result
|
|
|
|
result="$(mysql_query "information_schema" \
|
|
"SELECT COUNT(*) FROM tables WHERE table_schema = '${database}' AND table_name = '${table_name}';")"
|
|
|
|
[[ "$result" == "1" ]]
|
|
}
|
|
|
|
database_exists() {
|
|
local database="$1"
|
|
local result
|
|
|
|
result="$(mysql_query "information_schema" \
|
|
"SELECT COUNT(*) FROM schemata WHERE schema_name = '${database}';")"
|
|
|
|
[[ "$result" == "1" ]]
|
|
}
|
|
|
|
import_sql_file() {
|
|
local database="$1"
|
|
local file_path="$2"
|
|
|
|
if [[ ! -f "$file_path" ]]; then
|
|
printf 'SQL file not found: %s\n' "$file_path" >&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_encounter_journal_sql() {
|
|
local schema_file="$ROOT_DIR/modules/mod-encounter-journal/data/sql/db-world/base/01_encounter_journal_schema.sql"
|
|
local sample_file="$ROOT_DIR/modules/mod-encounter-journal/data/sql/db-world/base/02_encounter_journal_sample.sql"
|
|
|
|
if [[ "$IMPORT_ENCOUNTER_JOURNAL_SQL" == "0" ]]; then
|
|
log "Encounter Journal SQL import disabled, skipped"
|
|
return 0
|
|
fi
|
|
|
|
if [[ ! -f "$schema_file" ]]; then
|
|
log "mod-encounter-journal schema SQL not found, skipped"
|
|
return 0
|
|
fi
|
|
|
|
# Schema file uses CREATE TABLE IF NOT EXISTS, but we still gate on the
|
|
# canonical tier table to avoid noisy re-imports on every bootstrap.
|
|
if ! table_exists "acore_world" "custom_ej_tier"; then
|
|
import_sql_file "acore_world" "$schema_file"
|
|
else
|
|
log "custom_ej_* schema already present, skipping"
|
|
fi
|
|
|
|
# Sample data only on a fresh install (no rows in any custom_ej_* table).
|
|
# Re-running it would clobber hand-edited rows in the 9000-9999 id range.
|
|
if [[ -f "$sample_file" ]]; then
|
|
local total
|
|
total="$(mysql_query "acore_world" "
|
|
SELECT (SELECT COUNT(*) FROM custom_ej_tier)
|
|
+ (SELECT COUNT(*) FROM custom_ej_instance)
|
|
+ (SELECT COUNT(*) FROM custom_ej_encounter)
|
|
+ (SELECT COUNT(*) FROM custom_ej_creature)
|
|
+ (SELECT COUNT(*) FROM custom_ej_section)
|
|
+ (SELECT COUNT(*) FROM custom_ej_loot);
|
|
")"
|
|
|
|
if [[ "$total" == "0" ]]; then
|
|
import_sql_file "acore_world" "$sample_file"
|
|
else
|
|
log "custom_ej_* tables already populated, skipping sample data"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
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"
|
|
require_integer_flag "ACORE_IMPORT_ENCOUNTER_JOURNAL_SQL" "$IMPORT_ENCOUNTER_JOURNAL_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_encounter_journal_sql
|
|
import_store_sql
|
|
|
|
log "custom SQL bootstrap completed"
|