mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-01-13 09:07:20 +00:00
adds pdump and 2fa generation
This commit is contained in:
344
scripts/bash/pdump-import.sh
Executable file
344
scripts/bash/pdump-import.sh
Executable file
@@ -0,0 +1,344 @@
|
||||
#!/bin/bash
|
||||
# Import character pdump files into AzerothCore database
|
||||
set -euo pipefail
|
||||
|
||||
INVOCATION_DIR="$PWD"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
COLOR_RED='\033[0;31m'
|
||||
COLOR_GREEN='\033[0;32m'
|
||||
COLOR_YELLOW='\033[1;33m'
|
||||
COLOR_BLUE='\033[0;34m'
|
||||
COLOR_RESET='\033[0m'
|
||||
|
||||
log(){ printf '%b\n' "${COLOR_GREEN}$*${COLOR_RESET}"; }
|
||||
warn(){ printf '%b\n' "${COLOR_YELLOW}$*${COLOR_RESET}"; }
|
||||
err(){ printf '%b\n' "${COLOR_RED}$*${COLOR_RESET}"; }
|
||||
info(){ printf '%b\n' "${COLOR_BLUE}$*${COLOR_RESET}"; }
|
||||
fatal(){ err "$*"; exit 1; }
|
||||
|
||||
MYSQL_PW=""
|
||||
PDUMP_FILE=""
|
||||
TARGET_ACCOUNT=""
|
||||
NEW_CHARACTER_NAME=""
|
||||
FORCE_GUID=""
|
||||
AUTH_DB="acore_auth"
|
||||
CHARACTERS_DB="acore_characters"
|
||||
DRY_RUN=false
|
||||
BACKUP_BEFORE=true
|
||||
|
||||
usage(){
|
||||
cat <<'EOF'
|
||||
Usage: ./pdump-import.sh [options]
|
||||
|
||||
Import character pdump files into AzerothCore database.
|
||||
|
||||
Required Options:
|
||||
-f, --file FILE Pdump file to import (.pdump or .sql format)
|
||||
-a, --account ACCOUNT Target account name or ID for character import
|
||||
-p, --password PASS MySQL root password
|
||||
|
||||
Optional:
|
||||
-n, --name NAME New character name (if different from dump)
|
||||
-g, --guid GUID Force specific character GUID
|
||||
--auth-db NAME Auth database schema name (default: acore_auth)
|
||||
--characters-db NAME Characters database schema name (default: acore_characters)
|
||||
--dry-run Validate pdump without importing
|
||||
--no-backup Skip pre-import backup (not recommended)
|
||||
-h, --help Show this help and exit
|
||||
|
||||
Examples:
|
||||
# Import character from pdump file
|
||||
./pdump-import.sh --file character.pdump --account testaccount --password azerothcore123
|
||||
|
||||
# Import with new character name
|
||||
./pdump-import.sh --file oldchar.pdump --account newaccount --name "NewCharName" --password azerothcore123
|
||||
|
||||
# Validate pdump file without importing
|
||||
./pdump-import.sh --file character.pdump --account testaccount --password azerothcore123 --dry-run
|
||||
|
||||
Notes:
|
||||
- Account must exist in the auth database before import
|
||||
- Character names must be unique across the server
|
||||
- Pre-import backup is created automatically (can be disabled with --no-backup)
|
||||
- Use --dry-run to validate pdump structure before actual import
|
||||
EOF
|
||||
}
|
||||
|
||||
validate_account(){
|
||||
local account="$1"
|
||||
if [[ "$account" =~ ^[0-9]+$ ]]; then
|
||||
# Account ID provided
|
||||
local count
|
||||
count=$(docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B -e \
|
||||
"SELECT COUNT(*) FROM ${AUTH_DB}.account WHERE id = $account;")
|
||||
[[ "$count" -eq 1 ]] || fatal "Account ID $account not found in auth database"
|
||||
else
|
||||
# Account name provided
|
||||
local count
|
||||
count=$(docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B -e \
|
||||
"SELECT COUNT(*) FROM ${AUTH_DB}.account WHERE username = '$account';")
|
||||
[[ "$count" -eq 1 ]] || fatal "Account '$account' not found in auth database"
|
||||
fi
|
||||
}
|
||||
|
||||
get_account_id(){
|
||||
local account="$1"
|
||||
if [[ "$account" =~ ^[0-9]+$ ]]; then
|
||||
echo "$account"
|
||||
else
|
||||
docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B -e \
|
||||
"SELECT id FROM ${AUTH_DB}.account WHERE username = '$account';"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_character_name(){
|
||||
local name="$1"
|
||||
# Check character name format (WoW naming rules)
|
||||
if [[ ! "$name" =~ ^[A-Za-z]{2,12}$ ]]; then
|
||||
fatal "Invalid character name: '$name'. Must be 2-12 letters, no numbers or special characters."
|
||||
fi
|
||||
|
||||
# Check if character name already exists
|
||||
local count
|
||||
count=$(docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B -e \
|
||||
"SELECT COUNT(*) FROM ${CHARACTERS_DB}.characters WHERE name = '$name';")
|
||||
[[ "$count" -eq 0 ]] || fatal "Character name '$name' already exists in database"
|
||||
}
|
||||
|
||||
get_next_guid(){
|
||||
docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B -e \
|
||||
"SELECT COALESCE(MAX(guid), 0) + 1 FROM ${CHARACTERS_DB}.characters;"
|
||||
}
|
||||
|
||||
validate_pdump_format(){
|
||||
local file="$1"
|
||||
if [[ ! -f "$file" ]]; then
|
||||
fatal "Pdump file not found: $file"
|
||||
fi
|
||||
|
||||
# Check if file is readable and has SQL-like content
|
||||
if ! head -10 "$file" | grep -q -i "INSERT\|UPDATE\|CREATE\|ALTER"; then
|
||||
warn "File does not appear to contain SQL statements. Continuing anyway..."
|
||||
fi
|
||||
|
||||
info "Pdump file validation: OK"
|
||||
}
|
||||
|
||||
backup_characters(){
|
||||
local timestamp
|
||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local backup_file="manual-backups/characters-pre-pdump-import-${timestamp}.sql"
|
||||
mkdir -p manual-backups
|
||||
|
||||
log "Creating backup: $backup_file"
|
||||
docker exec ac-mysql mysqldump -uroot -p"$MYSQL_PW" "$CHARACTERS_DB" > "$backup_file"
|
||||
echo "$backup_file"
|
||||
}
|
||||
|
||||
process_pdump_sql(){
|
||||
local file="$1"
|
||||
local account_id="$2"
|
||||
local new_guid="${3:-}"
|
||||
local new_name="${4:-}"
|
||||
|
||||
# Create temporary processed file
|
||||
local temp_file
|
||||
temp_file=$(mktemp)
|
||||
|
||||
# Process the pdump SQL file
|
||||
# Replace account references and optionally GUID/name
|
||||
if [[ -n "$new_guid" && -n "$new_name" ]]; then
|
||||
sed -e "s/\([^0-9]\)[0-9]\+\([^0-9].*account.*=\)/\1${account_id}\2/g" \
|
||||
-e "s/\([^0-9]\)[0-9]\+\([^0-9].*guid.*=\)/\1${new_guid}\2/g" \
|
||||
-e "s/'[^']*'\([^']*name.*=\)/'${new_name}'\1/g" \
|
||||
"$file" > "$temp_file"
|
||||
elif [[ -n "$new_guid" ]]; then
|
||||
sed -e "s/\([^0-9]\)[0-9]\+\([^0-9].*account.*=\)/\1${account_id}\2/g" \
|
||||
-e "s/\([^0-9]\)[0-9]\+\([^0-9].*guid.*=\)/\1${new_guid}\2/g" \
|
||||
"$file" > "$temp_file"
|
||||
elif [[ -n "$new_name" ]]; then
|
||||
sed -e "s/\([^0-9]\)[0-9]\+\([^0-9].*account.*=\)/\1${account_id}\2/g" \
|
||||
-e "s/'[^']*'\([^']*name.*=\)/'${new_name}'\1/g" \
|
||||
"$file" > "$temp_file"
|
||||
else
|
||||
sed -e "s/\([^0-9]\)[0-9]\+\([^0-9].*account.*=\)/\1${account_id}\2/g" \
|
||||
"$file" > "$temp_file"
|
||||
fi
|
||||
|
||||
echo "$temp_file"
|
||||
}
|
||||
|
||||
import_pdump(){
|
||||
local processed_file="$1"
|
||||
|
||||
log "Importing character data into $CHARACTERS_DB database"
|
||||
if docker exec -i ac-mysql mysql -uroot -p"$MYSQL_PW" "$CHARACTERS_DB" < "$processed_file"; then
|
||||
log "Character import completed successfully"
|
||||
else
|
||||
fatal "Character import failed. Check MySQL logs for details."
|
||||
fi
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
-h|--help) usage; exit 0;;
|
||||
esac
|
||||
|
||||
# Parse command line arguments
|
||||
POSITIONAL=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-f|--file)
|
||||
[[ $# -ge 2 ]] || fatal "--file requires a file path"
|
||||
PDUMP_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
-a|--account)
|
||||
[[ $# -ge 2 ]] || fatal "--account requires an account name or ID"
|
||||
TARGET_ACCOUNT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p|--password)
|
||||
[[ $# -ge 2 ]] || fatal "--password requires a value"
|
||||
MYSQL_PW="$2"
|
||||
shift 2
|
||||
;;
|
||||
-n|--name)
|
||||
[[ $# -ge 2 ]] || fatal "--name requires a character name"
|
||||
NEW_CHARACTER_NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
-g|--guid)
|
||||
[[ $# -ge 2 ]] || fatal "--guid requires a GUID number"
|
||||
FORCE_GUID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--auth-db)
|
||||
[[ $# -ge 2 ]] || fatal "--auth-db requires a value"
|
||||
AUTH_DB="$2"
|
||||
shift 2
|
||||
;;
|
||||
--characters-db)
|
||||
[[ $# -ge 2 ]] || fatal "--characters-db requires a value"
|
||||
CHARACTERS_DB="$2"
|
||||
shift 2
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--no-backup)
|
||||
BACKUP_BEFORE=false
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
while [[ $# -gt 0 ]]; do
|
||||
POSITIONAL+=("$1")
|
||||
shift
|
||||
done
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
fatal "Unknown option: $1"
|
||||
;;
|
||||
*)
|
||||
POSITIONAL+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate required arguments
|
||||
[[ -n "$PDUMP_FILE" ]] || fatal "Pdump file is required. Use --file FILE"
|
||||
[[ -n "$TARGET_ACCOUNT" ]] || fatal "Target account is required. Use --account ACCOUNT"
|
||||
[[ -n "$MYSQL_PW" ]] || fatal "MySQL password is required. Use --password PASS"
|
||||
|
||||
# Resolve relative paths
|
||||
if [[ ! "$PDUMP_FILE" =~ ^/ ]]; then
|
||||
PDUMP_FILE="$INVOCATION_DIR/$PDUMP_FILE"
|
||||
fi
|
||||
|
||||
# Validate inputs
|
||||
log "Validating pdump file..."
|
||||
validate_pdump_format "$PDUMP_FILE"
|
||||
|
||||
log "Validating target account..."
|
||||
validate_account "$TARGET_ACCOUNT"
|
||||
ACCOUNT_ID=$(get_account_id "$TARGET_ACCOUNT")
|
||||
log "Target account ID: $ACCOUNT_ID"
|
||||
|
||||
if [[ -n "$NEW_CHARACTER_NAME" ]]; then
|
||||
log "Validating new character name..."
|
||||
validate_character_name "$NEW_CHARACTER_NAME"
|
||||
fi
|
||||
|
||||
# Determine GUID
|
||||
if [[ -n "$FORCE_GUID" ]]; then
|
||||
CHARACTER_GUID="$FORCE_GUID"
|
||||
log "Using forced GUID: $CHARACTER_GUID"
|
||||
else
|
||||
CHARACTER_GUID=$(get_next_guid)
|
||||
log "Using next available GUID: $CHARACTER_GUID"
|
||||
fi
|
||||
|
||||
# Process pdump file
|
||||
log "Processing pdump file..."
|
||||
PROCESSED_FILE=$(process_pdump_sql "$PDUMP_FILE" "$ACCOUNT_ID" "$CHARACTER_GUID" "$NEW_CHARACTER_NAME")
|
||||
|
||||
if $DRY_RUN; then
|
||||
info "DRY RUN: Pdump processing completed successfully"
|
||||
info "Processed file saved to: $PROCESSED_FILE"
|
||||
info "Account ID: $ACCOUNT_ID"
|
||||
info "Character GUID: $CHARACTER_GUID"
|
||||
[[ -n "$NEW_CHARACTER_NAME" ]] && info "Character name: $NEW_CHARACTER_NAME"
|
||||
info "Run without --dry-run to perform actual import"
|
||||
rm -f "$PROCESSED_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create backup before import
|
||||
BACKUP_FILE=""
|
||||
if $BACKUP_BEFORE; then
|
||||
BACKUP_FILE=$(backup_characters)
|
||||
fi
|
||||
|
||||
# Stop world server to prevent issues during import
|
||||
log "Stopping world server for safe import..."
|
||||
docker stop ac-worldserver >/dev/null 2>&1 || warn "World server was not running"
|
||||
|
||||
# Perform import
|
||||
trap 'rm -f "$PROCESSED_FILE"' EXIT
|
||||
import_pdump "$PROCESSED_FILE"
|
||||
|
||||
# Restart world server
|
||||
log "Restarting world server..."
|
||||
docker start ac-worldserver >/dev/null 2>&1
|
||||
|
||||
# Wait for server to initialize
|
||||
log "Waiting for world server to initialize..."
|
||||
for i in {1..30}; do
|
||||
if docker exec ac-worldserver pgrep worldserver >/dev/null 2>&1; then
|
||||
log "World server is running"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 30 ]; then
|
||||
warn "World server took longer than expected to start"
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Verify import
|
||||
CHARACTER_COUNT=$(docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B -e \
|
||||
"SELECT COUNT(*) FROM ${CHARACTERS_DB}.characters WHERE account = $ACCOUNT_ID;")
|
||||
|
||||
log "Import completed successfully!"
|
||||
log "Characters on account $TARGET_ACCOUNT: $CHARACTER_COUNT"
|
||||
[[ -n "$BACKUP_FILE" ]] && log "Backup created: $BACKUP_FILE"
|
||||
|
||||
info "Character import from pdump completed. You can now log in and play!"
|
||||
Reference in New Issue
Block a user