├── app ├── .keep ├── sql │ ├── backup │ │ └── .keep │ ├── custom │ │ └── .keep │ ├── fixes │ │ └── .keep │ ├── install │ │ └── .keep │ ├── misc │ │ ├── world_shop_set_all_prices_zero.sql │ │ └── world_shop_add_invincible.sql │ └── templates │ │ ├── uninstall_db_template.sql │ │ ├── init_db_template.sql │ │ └── auth_update_template.sql └── custom_conf │ ├── custom_crossfaction.conf │ ├── README.md │ └── custom_ahbot.conf ├── src └── .keep ├── docker ├── authserver │ ├── entrypoint.sh │ └── Dockerfile ├── worldserver │ ├── entrypoint.sh │ └── Dockerfile └── utility │ ├── utility │ ├── commands │ ├── backup_db.sh │ ├── install_all_sql.sh │ ├── apply_custom_config.sh │ ├── restore_db.sh │ ├── extract_data.sh │ ├── configure.sh │ ├── compile.sh │ ├── exec_sql.sh │ └── build_sql_bundles.sh │ └── Dockerfile ├── .gitignore ├── misc └── configure_client.sh ├── docker-compose.yaml ├── env.dist ├── Makefile └── README.md /app/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/sql/backup/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/sql/custom/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/sql/fixes/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/sql/install/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/sql/misc/world_shop_set_all_prices_zero.sql: -------------------------------------------------------------------------------- 1 | -- Set all BattlePay shop product prices to 0 (make everything free) 2 | 3 | UPDATE `battle_pay_product` 4 | SET `price` = 0, `discount` = 0; -------------------------------------------------------------------------------- /docker/authserver/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Default command can be overridden with ENV START_CMD 3 | CMD=${START_AUTH} 4 | 5 | # Execute the command (pass through any extra args from `docker run`) 6 | exec $CMD "$@" -------------------------------------------------------------------------------- /docker/worldserver/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Default command can be overridden with ENV START_CMD 3 | CMD=${START_WORLD} 4 | 5 | # Execute the command (pass through any extra args from `docker run`) 6 | exec $CMD "$@" -------------------------------------------------------------------------------- /app/sql/templates/uninstall_db_template.sql: -------------------------------------------------------------------------------- 1 | -- Drops existing databases and user for a clean setup. 2 | 3 | DROP DATABASE IF EXISTS ${AUTH_DB}; 4 | DROP DATABASE IF EXISTS ${WORLD_DB}; 5 | DROP DATABASE IF EXISTS ${CHARACTER_DB}; 6 | DROP USER IF EXISTS '${SERVER_DB_USER}'@'%'; 7 | 8 | FLUSH PRIVILEGES; -------------------------------------------------------------------------------- /docker/utility/utility: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COMMAND="$1" 4 | shift 5 | 6 | SCRIPT="/bin/commands/${COMMAND}.sh" 7 | 8 | if [ -x "$SCRIPT" ]; then 9 | exec "$SCRIPT" "$@" 10 | else 11 | # echo "No command script found for: $COMMAND, running directly..." 12 | exec "$COMMAND" "$@" 13 | fi -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in app except for custom and sql_fixes 2 | app/** 3 | !app/sql 4 | !app/custom_conf 5 | 6 | !app/sql/** 7 | !app/custom_conf/** 8 | 9 | 10 | # Ignore all contents in backup ad src 11 | app/sql/backup/** 12 | app/sql/install/** 13 | src/** 14 | 15 | # Always keep .keep files everywhere 16 | !**/.keep 17 | 18 | # General ignores 19 | *.log 20 | *.tmp 21 | *.bak 22 | .DS_Store 23 | TODO* 24 | .env 25 | 26 | -------------------------------------------------------------------------------- /app/custom_conf/custom_crossfaction.conf: -------------------------------------------------------------------------------- 1 | # Allow cross-faction interaction 2 | AllowTwoSide.Accounts = 1 3 | AllowTwoSide.Interaction.Chat = 1 4 | AllowTwoSide.Interaction.Channel = 1 5 | AllowTwoSide.Interaction.Group = 1 6 | AllowTwoSide.Interaction.Guild = 1 7 | AllowTwoSide.Interaction.Auction = 1 8 | AllowTwoSide.Interaction.Mail = 1 9 | AllowTwoSide.WhoList = 1 10 | AllowTwoSide.AddFriend = 1 11 | AllowTwoSide.Interaction.DungeonFinder = 1 12 | 13 | # EOF -------------------------------------------------------------------------------- /docker/utility/commands/backup_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Generate timestamped backup directory 5 | DATE=$(date +"%Y%m%d_%H%M%S") 6 | BACKUP_DIR="${SQL_INSTALL_DIR}/backup/${PROJECT_NAME}_${DATE}" 7 | mkdir -p "$BACKUP_DIR" 8 | 9 | echo "=== Backing up ${PROJECT_NAME} databases ===" 10 | 11 | # Dump all relevant databases 12 | for DB in "$AUTH_DB" "$CHARACTER_DB" "$WORLD_DB"; do 13 | echo "--- Dumping $DB ---" 14 | mysqldump \ 15 | -h "$DB_HOST" \ 16 | -P "$DB_PORT" \ 17 | -u "$MYSQL_USERNAME" \ 18 | -p"$MYSQL_PASSWORD" \ 19 | "$DB" > "$BACKUP_DIR/$DB.sql" 20 | done 21 | 22 | echo "=== Backups stored in: $BACKUP_DIR ===" 23 | -------------------------------------------------------------------------------- /app/sql/templates/init_db_template.sql: -------------------------------------------------------------------------------- 1 | -- Drop old databases and user if they exist 2 | DROP DATABASE IF EXISTS ${AUTH_DB}; 3 | DROP DATABASE IF EXISTS ${WORLD_DB}; 4 | DROP DATABASE IF EXISTS ${CHARACTER_DB}; 5 | DROP USER IF EXISTS '${SERVER_DB_USER}'@'%'; 6 | 7 | -- Create fresh databases 8 | CREATE DATABASE ${AUTH_DB}; 9 | CREATE DATABASE ${WORLD_DB}; 10 | CREATE DATABASE ${CHARACTER_DB}; 11 | 12 | -- Recreate user and grant access 13 | CREATE USER '${SERVER_DB_USER}'@'%' IDENTIFIED BY '${SERVER_DB_PASSWORD}'; 14 | GRANT ALL PRIVILEGES ON ${AUTH_DB}.* TO '${SERVER_DB_USER}'@'%'; 15 | GRANT ALL PRIVILEGES ON ${WORLD_DB}.* TO '${SERVER_DB_USER}'@'%'; 16 | GRANT ALL PRIVILEGES ON ${CHARACTER_DB}.* TO '${SERVER_DB_USER}'@'%'; 17 | FLUSH PRIVILEGES; -------------------------------------------------------------------------------- /docker/authserver/Dockerfile: -------------------------------------------------------------------------------- 1 | # Select base image (default: Debian 12 / bookworm) 2 | ARG BASE_IMAGE=debian:bookworm-slim 3 | FROM ${BASE_IMAGE} 4 | 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | # Install runtime libraries only 8 | RUN apt-get update && apt-get install -y \ 9 | libace-dev \ 10 | libssl3 \ 11 | libmariadb3 \ 12 | libreadline8 \ 13 | libncurses6 \ 14 | && rm -rf /var/lib/apt/lists/* 15 | 16 | # Copy entrypoint script 17 | COPY entrypoint.sh /entrypoint.sh 18 | RUN chmod +x /entrypoint.sh 19 | 20 | # Default working directory 21 | WORKDIR /app 22 | 23 | # Default command (can be overridden by ENV) 24 | ENV START_AUTH="./bin/authserver" 25 | 26 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /docker/worldserver/Dockerfile: -------------------------------------------------------------------------------- 1 | # Select base image (default: Debian 12 / bookworm) 2 | ARG BASE_IMAGE=debian:bookworm-slim 3 | FROM ${BASE_IMAGE} 4 | 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | # Install runtime libraries only 8 | RUN apt-get update && apt-get install -y \ 9 | libace-dev \ 10 | libssl3 \ 11 | libmariadb3 \ 12 | libreadline8 \ 13 | libncurses6 \ 14 | && rm -rf /var/lib/apt/lists/* 15 | 16 | # Copy entrypoint script 17 | COPY entrypoint.sh /entrypoint.sh 18 | RUN chmod +x /entrypoint.sh 19 | 20 | # Default working directory 21 | WORKDIR /app 22 | 23 | # Default command (can be overridden by ENV) 24 | ENV START_AUTH="./bin/worldserver" 25 | 26 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /docker/utility/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE=debian:bookworm-slim 2 | FROM ${BASE_IMAGE} 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Set timezone if $TZ is provided 7 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 8 | 9 | # Install compilers, build tools, and dev libraries (Bookworm versions) 10 | RUN apt-get update && apt-get install -y \ 11 | tzdata vim tmux git \ 12 | clang clang-tools lldb \ 13 | libreadline-dev cmake libssl-dev make gcc g++ \ 14 | libboost-all-dev libace-dev libbz2-dev unzip wget \ 15 | default-mysql-client default-libmysqlclient-dev \ 16 | && rm -rf /var/lib/apt/lists/* 17 | 18 | # Copy dispatcher script (utility entrypoint) 19 | COPY utility /bin/utility 20 | RUN chmod +x /bin/utility 21 | 22 | # Copy all command scripts (e.g., compile.sh, init_db.sh, etc.) 23 | COPY commands/ /bin/commands/ 24 | RUN chmod +x /bin/commands/*.sh 25 | 26 | # Set dispatcher as entrypoint 27 | ENTRYPOINT ["/bin/utility"] -------------------------------------------------------------------------------- /docker/utility/commands/install_all_sql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Expect PROJECT_NAME and SQL_INSTALL_DIR from container environment 5 | 6 | # All SQL files to be processed (can be overridden by env var if needed) 7 | FILES=" 8 | auth_base.sql 9 | characters_base.sql 10 | world_base.sql 11 | auth_patches_update.sql 12 | auth_fixes.sql 13 | characters_patches_update.sql 14 | characters_fixes.sql 15 | world_update.sql 16 | world_patches_update.sql 17 | world_fixes.sql 18 | auth_custom.sql 19 | characters_custom.sql 20 | world_custom.sql 21 | " 22 | 23 | echo "=== Installing all SQL files in order for $PROJECT_NAME ===" 24 | 25 | for FILE in $FILES; do 26 | FULL_PATH="$SQL_INSTALL_DIR/$FILE" 27 | 28 | if [ ! -f "$FULL_PATH" ]; then 29 | echo "Warning: $FILE not found in $SQL_INSTALL_DIR, skipping." 30 | continue 31 | fi 32 | 33 | echo "Installing $FILE..." 34 | if ! /bin/commands/exec_sql.sh install "$FILE"; then 35 | echo "Error: Failed to execute $FILE (stopping)." 36 | exit 1 37 | fi 38 | done 39 | 40 | echo "=== All SQL installation complete ===" 41 | -------------------------------------------------------------------------------- /app/custom_conf/README.md: -------------------------------------------------------------------------------- 1 | ### `/app/custom` – Custom Configuration 2 | 3 | This directory is used for **custom configuration files** that can modify `authserver.conf` and `worldserver.conf` without manually editing them. 4 | 5 | - Place one or more configuration files in this directory. 6 | - Each line in a file must follow the format: 7 | 8 | Key = Value 9 | 10 | Example: 11 | AllowTwoSide.Interaction.Guild = 1 12 | AuctionHouseBot.Seller.Enabled = 1 13 | 14 | - To apply the changes, run: 15 | 16 | make apply_custom_config (applies all files in the directory) 17 | make apply_custom_config FILE=world.conf (applies only the specified file) 18 | 19 | to apply without make use: 20 | docker compose run --rm utility /bin/commands/apply_custom_config.sh /app/custom/world.conf 21 | 22 | 23 | 24 | All values defined in these files will overwrite existing values in the configuration files. 25 | 26 | Example configs you can create: 27 | - **crossfaction.conf**: Enables cross-faction play (group, guild, chat, mail, auction house). 28 | - **ahbot.conf**: Activates and tunes the Auction House Bot. 29 | 30 | This system allows you to easily customize your server behavior without touching the default configuration files. -------------------------------------------------------------------------------- /misc/configure_client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | WOW_PATH=$1 5 | WOW_LOCALE="$2" 6 | REALM_ADDRESS="$3" 7 | 8 | REALMLIST_PATH=$WOW_PATH/Data/$WOW_LOCALE/realmlist.wtf 9 | CONFIG_PATH="$WOW_PATH/WTF/Config.wtf" 10 | 11 | echo "Configuring WoW client at: $WOW_PATH" 12 | echo "Locale: $WOW_LOCALE" 13 | echo "Realm Address: $REALM_ADDRESS" 14 | 15 | # Ensure directories exist 16 | mkdir -p "$(dirname "$REALMLIST_PATH")" 17 | mkdir -p "$(dirname "$CONFIG_PATH")" 18 | 19 | # Backup existing files if they exist 20 | [ -f "$REALMLIST_PATH" ] && cp "$REALMLIST_PATH" "$REALMLIST_PATH.bak" 21 | [ -f "$CONFIG_PATH" ] && cp "$CONFIG_PATH" "$CONFIG_PATH.bak" 22 | 23 | # Overwrite realmlist.wtf 24 | echo "SET realmlist $REALM_ADDRESS" > "$REALMLIST_PATH" 25 | echo "Updated $REALMLIST_PATH" 26 | 27 | # Update or append SET realmlist in Config.wtf 28 | if [ -f "$CONFIG_PATH" ]; then 29 | # Replace if line exists, otherwise append 30 | if grep -q '^SET realmlist ' "$CONFIG_PATH"; then 31 | sed -i "s|^SET realmlist .*|SET realmlist \"$REALM_ADDRESS\"|" "$CONFIG_PATH" 32 | else 33 | echo "SET realmlist \"$REALM_ADDRESS\"" >> "$CONFIG_PATH" 34 | fi 35 | else 36 | echo "SET realmlist \"$REALM_ADDRESS\"" > "$CONFIG_PATH" 37 | fi 38 | 39 | echo "Updated $CONFIG_PATH" 40 | echo "WoW client configuration complete." 41 | -------------------------------------------------------------------------------- /app/custom_conf/custom_ahbot.conf: -------------------------------------------------------------------------------- 1 | # Enable the Auction House Bot 2 | AuctionHouseBot.Seller.Enabled = 1 3 | 4 | # Make all factions share Auction Houses 5 | AuctionHouseBot.Alliance.Items.Amount.Ratio = 100 6 | AuctionHouseBot.Horde.Items.Amount.Ratio = 100 7 | AuctionHouseBot.Neutral.Items.Amount.Ratio = 100 8 | 9 | # Lower all prices to 50% 10 | AuctionHouseBot.Alliance.Price.Ratio = 50 11 | AuctionHouseBot.Horde.Price.Ratio = 50 12 | AuctionHouseBot.Neutral.Price.Ratio = 50 13 | 14 | # Allow more items per quality 15 | AuctionHouseBot.Items.Amount.Gray = 500 16 | AuctionHouseBot.Items.Amount.White = 5000 17 | AuctionHouseBot.Items.Amount.Green = 5000 18 | AuctionHouseBot.Items.Amount.Blue = 3000 19 | AuctionHouseBot.Items.Amount.Purple = 1500 20 | AuctionHouseBot.Items.Amount.Orange = 200 21 | AuctionHouseBot.Items.Amount.Yellow = 100 22 | 23 | # Speed up auction house population 24 | AuctionHouseBot.ItemsPerCycle.Boost = 5000 25 | AuctionHouseBot.ItemsPerCycle.Normal = 1000 26 | 27 | # Allow more trade goods, misc, consumables, etc. 28 | AuctionHouseBot.Class.Consumable = 10 29 | AuctionHouseBot.Class.TradeGood = 10 30 | AuctionHouseBot.Class.Misc = 10 31 | AuctionHouseBot.Class.RandomStackRatio.TradeGood = 100 32 | 33 | # Short auction durations for high turnover 34 | AuctionHouseBot.MinTime = 1 35 | AuctionHouseBot.MaxTime = 12 36 | 37 | # Do not exclude any items 38 | AuctionHouseBot.forceExcludeItems = "" 39 | 40 | # EOF -------------------------------------------------------------------------------- /app/sql/misc/world_shop_add_invincible.sql: -------------------------------------------------------------------------------- 1 | -- Add Invincible's Reins (Icecrown Citadel mount) to BattlePay shop (Free) 2 | 3 | -- Step 1: Add to shop entry (visible in Mounts group) 4 | INSERT INTO `battle_pay_entry` 5 | (`id`, `productId`, `groupId`, `idx`, `title`, `description`, `icon`, `displayId`, `banner`, `flags`) 6 | VALUES 7 | (200, 200, 2, 0, 8 | '|cffa335eeInvincible''s Reins|r', 9 | 'Flying mount from Icecrown Citadel (Lich King)', 10 | '294032', -- icon (Ironbound proto-drake style icon, change if needed) 11 | 28953, -- displayId (Invincible’s Reins visual model) 12 | 2, -- banner type (matches mounts) 13 | 0); -- flags (default) 14 | 15 | -- Step 2: Define product (price set to 0 for free) 16 | INSERT INTO `battle_pay_product` 17 | (`id`, `title`, `description`, `icon`, `price`, `discount`, `displayId`, `type`, `choiceType`, `flags`, `flagsInfo`) 18 | VALUES 19 | (200, 20 | 'Shop: Invincible''s Reins', 21 | 'Flying mount from Icecrown Citadel (Lich King)', 22 | '294032', -- icon 23 | 0, -- price (0 = free) 24 | 0, -- discount 25 | 28953, -- displayId (matches above) 26 | 0, -- type (0 = mount/pet) 27 | 1, -- choiceType (1 = single purchase) 28 | 47, -- flags (same as other mounts) 29 | 0); -- flagsInfo 30 | 31 | -- Step 3: Link product to the actual mount item (Invincible’s Reins itemId: 50818) 32 | INSERT INTO `battle_pay_product_items` 33 | (`id`, `itemId`, `count`, `productId`) 34 | VALUES 35 | (200, 50818, 1, 200); -------------------------------------------------------------------------------- /app/sql/templates/auth_update_template.sql: -------------------------------------------------------------------------------- 1 | -- update_auth_template.sql 2 | -- Cleans up the auth database, creates admin account, and updates the realmlist. 3 | 4 | -- Clean up old accounts 5 | DELETE FROM account; 6 | DELETE FROM account_access; 7 | 8 | -- Add admin account (username: ADMIN, password: ADMIN) 9 | INSERT INTO account (id, username, sha_pass_hash) 10 | VALUES (1, 'ADMIN', '8301316D0D8448A34FA6D0C6BF1CBFA2B4A1A93A'); 11 | 12 | INSERT INTO account_access (id, gmlevel, RealmID) 13 | VALUES (1, 3, -1); 14 | 15 | -- Update realmlist 16 | DELETE FROM realmlist; 17 | 18 | INSERT INTO realmlist ( 19 | id, name, project_shortname, address, port, icon, color, timezone, 20 | allowedSecurityLevel, population, gamebuild, flag, 21 | project_hidden, project_enabled, project_dbname, project_dbworld, 22 | project_dbarchive, project_rates_min, project_rates_max, 23 | project_transfer_level_max, project_transfer_items, 24 | project_transfer_skills_spells, project_transfer_glyphs, 25 | project_transfer_achievements, project_server_same, 26 | project_server_settings, project_server_remote_path, 27 | project_accounts_detach, project_setskills_value_max, 28 | project_chat_enabled, project_statistics_enabled 29 | ) VALUES ( 30 | 1, '${REALM_NAME}', '${REALM_NAME}', '${REALM_ADDRESS}', ${REALM_PORT}, 31 | ${REALM_ICON}, ${REALM_COLOR}, ${REALM_TIMEZONE}, 32 | ${REALM_SECURITY}, ${REALM_POP}, ${REALM_BUILD}, ${REALM_FLAG}, 33 | 0, 1, '', '', '', 34 | 0, 0, 80, 'IGNORE', 'IGNORE', 'IGNORE', 'IGNORE', 35 | 0, '0', '0', 1, 0, 0, 0 36 | ); -------------------------------------------------------------------------------- /docker/utility/commands/apply_custom_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Apply custom configuration files to authserver.conf and worldserver.conf 5 | # Uses CUSTOM_DIR (for input) and ETC_DIR_PATH (for target configs) from .env 6 | 7 | echo "=== Applying custom configs to project ${PROJECT_NAME} ===" 8 | 9 | if [ -z "$CUSTOM_DIR" ] || [ -z "$ETC_DIR_PATH" ]; then 10 | echo "Error: CUSTOM_DIR or ETC_DIR_PATH is not set. Check your .env file." 11 | exit 1 12 | fi 13 | 14 | # If a specific config file is provided as argument, only process that file 15 | if [ -n "$1" ]; then 16 | FILES="$CUSTOM_DIR/$1" 17 | else 18 | FILES="$CUSTOM_DIR"/*.conf 19 | fi 20 | 21 | for FILE in $FILES; do 22 | [ -f "$FILE" ] || continue 23 | echo "Applying custom config from: $FILE" 24 | 25 | while IFS= read -r LINE; do 26 | # Skip empty lines and comments 27 | [ -z "$LINE" ] && continue 28 | echo "$LINE" | grep -qE '^\s*#' && continue 29 | 30 | KEY=$(echo "$LINE" | cut -d'=' -f1 | xargs) 31 | VALUE=$(echo "$LINE" | cut -d'=' -f2- | xargs) 32 | 33 | # Update value in target config files (authserver.conf & worldserver.conf) 34 | for TARGET in "$ETC_DIR_PATH/authserver.conf" "$ETC_DIR_PATH/worldserver.conf"; do 35 | if grep -q "^$KEY" "$TARGET"; then 36 | sed -i "s|^$KEY.*|$KEY = $VALUE|" "$TARGET" 37 | else 38 | echo "$KEY = $VALUE" >> "$TARGET" 39 | fi 40 | done 41 | done < "$FILE" 42 | done 43 | 44 | echo "=== Custom configs applied successfully ===" 45 | -------------------------------------------------------------------------------- /docker/utility/commands/restore_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "=== Restoring ${PROJECT_NAME} databases ===" 5 | 6 | BACKUP_DIR="/app/sql/backup" 7 | DB_HOST="${DB_HOST:?DB_HOST not set}" 8 | DB_PORT="${DB_PORT:?DB_PORT not set}" 9 | ROOT_USER="${MYSQL_USERNAME:?MYSQL_USERNAME not set}" 10 | ROOT_PASS="${MYSQL_PASSWORD:?MYSQL_PASSWORD not set}" 11 | 12 | # Use provided backup folder or auto-detect latest 13 | if [ -n "$BACKUP" ]; then 14 | BACKUP_PATH="$BACKUP_DIR/$BACKUP" 15 | else 16 | LATEST_BACKUP=$(ls -1 "$BACKUP_DIR" | sort | tail -n 1) 17 | BACKUP_PATH="$BACKUP_DIR/$LATEST_BACKUP" 18 | fi 19 | 20 | if [ ! -d "$BACKUP_PATH" ]; then 21 | echo "Backup directory $BACKUP_PATH not found." 22 | exit 1 23 | fi 24 | 25 | echo "Using backup: $BACKUP_PATH" 26 | 27 | # Function to drop and recreate database 28 | reset_db() { 29 | local db="$1" 30 | echo "Resetting database $db..." 31 | mysql -h "$DB_HOST" -P "$DB_PORT" -u "$ROOT_USER" -p"$ROOT_PASS" -e "DROP DATABASE IF EXISTS \`$db\`; CREATE DATABASE \`$db\` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;" 32 | } 33 | 34 | # Restore all three databases 35 | for DB in "$AUTH_DB" "$CHARACTER_DB" "$WORLD_DB"; do 36 | DUMP_FILE="$BACKUP_PATH/${DB}.sql" 37 | reset_db "$DB" 38 | if [ -f "$DUMP_FILE" ]; then 39 | echo "Restoring $DB from $DUMP_FILE..." 40 | mysql -h "$DB_HOST" -P "$DB_PORT" -u "$ROOT_USER" -p"$ROOT_PASS" "$DB" < "$DUMP_FILE" 41 | echo "Restored $DB successfully." 42 | else 43 | echo "Warning: No dump file for $DB at $DUMP_FILE" 44 | fi 45 | done 46 | 47 | echo "=== Database restore complete ===" -------------------------------------------------------------------------------- /docker/utility/commands/extract_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "=== Starting data extraction for $PROJECT_NAME ===" 5 | 6 | # Cleanup temporary files 7 | echo "--- Cleaning up temporary files ---" 8 | rm -rf "$WOW_INTERNAL/Buildings" || true 9 | rm -f "$WOW_INTERNAL/vmap4extractor" || true 10 | 11 | # Creating directories if needed 12 | BIN_DIR="$INSTALL_PREFIX/bin" 13 | DATA_DIR="$INSTALL_PREFIX/data" 14 | mkdir -p "$DATA_DIR" 15 | 16 | # Extract basic game data (DBC, Camera, and Maps) 17 | cd "$BIN_DIR" 18 | 19 | if [ "$MAPS" = "ON" ]; then 20 | rm -rf "$DATA_DIR/dbc" || true 21 | 22 | echo "--- Extracting DBC, Camera, and Maps ---" 23 | ./mapextractor -i "$WOW_INTERNAL" -o "$DATA_DIR" 24 | 25 | echo "--- Fixing DBC filenames ---" 26 | if [ -d "$DATA_DIR/dbc" ]; then 27 | find "$DATA_DIR/dbc" -type f -name '*\\*' | while read -r file; do 28 | fixed_name=$(echo "$file" | tr -d '\\') 29 | if [ "$file" != "$fixed_name" ]; then 30 | mv "$file" "$fixed_name" 31 | echo "Renamed: $file -> $fixed_name" 32 | fi 33 | done 34 | fi 35 | fi 36 | 37 | # Extract and assemble VMAPS 38 | if [ "$VMAPS" = "ON" ]; then 39 | echo "--- Extracting VMAPS ---" 40 | rm -rf "$DATA_DIR/vmaps" || true 41 | mkdir -p "$DATA_DIR/vmaps" 42 | cp "$BIN_DIR/vmap4extractor" "$WOW_INTERNAL/" 43 | cd "$WOW_INTERNAL" 44 | ./vmap4extractor -l -b "$DATA_DIR" 45 | 46 | echo "--- Assembling VMAPS ---" 47 | cd "$BIN_DIR" 48 | ./vmap4assembler "$WOW_INTERNAL/Buildings" "$DATA_DIR/vmaps" 49 | fi 50 | 51 | # Generate MMAPS 52 | if [ "$MMAPS" = "ON" ]; then 53 | echo "--- Generating MMAPS ---" 54 | rm -rf "$DATA_DIR/mmaps" || true 55 | mkdir -p "$DATA_DIR/mmaps" 56 | cp "$BIN_DIR/mmaps_generator" "$DATA_DIR" 57 | cd "$DATA_DIR" 58 | ./mmaps_generator 59 | fi 60 | 61 | # Cleanup temporary files 62 | echo "--- Cleaning up temporary files ---" 63 | rm -rf "$WOW_INTERNAL/Buildings" || true 64 | rm -rf "$BIN_DIR/Buildings" || true 65 | rm -f "$WOW_INTERNAL/vmap4extractor" || true 66 | rm -f "$DATA_DIR/mmaps_generator" || true 67 | 68 | echo "=== Data extraction complete ===" 69 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | utility: 3 | image: ${IMAGE_NAME}-utility:${OS_NAME} 4 | container_name: ${CONTAINER_NAME}-utility 5 | env_file: 6 | - ./.env 7 | build: 8 | context: docker/utility 9 | dockerfile: Dockerfile 10 | volumes: 11 | - "./app:/app:rw" 12 | - "./src:/src:rw" 13 | - "./app/sql/backup:/backup:rw" 14 | - "${WOW_PATH}:/app/wow:rw" 15 | tty: true 16 | restart: "no" 17 | profiles: 18 | - utility 19 | 20 | authserver: 21 | image: ${IMAGE_NAME}-authserver:${OS_NAME} 22 | container_name: ${CONTAINER_NAME}-authserver 23 | env_file: 24 | - ./.env 25 | build: 26 | context: docker/authserver 27 | dockerfile: Dockerfile 28 | args: 29 | BASE_IMAGE: ${BASE_IMAGE} 30 | volumes: 31 | - "./app:/app:rw" 32 | ports: 33 | - "${AUTH_PORT}:3724" 34 | restart: unless-stopped 35 | 36 | worldserver: 37 | image: ${IMAGE_NAME}-worldserver:${OS_NAME} 38 | container_name: ${CONTAINER_NAME}-worldserver 39 | env_file: 40 | - ./.env 41 | build: 42 | context: docker/worldserver 43 | dockerfile: Dockerfile 44 | args: 45 | BASE_IMAGE: ${BASE_IMAGE} 46 | volumes: 47 | - "./app:/app:rw" 48 | ports: 49 | - "${RA_PORT}:3443" 50 | - "${SOAP_PORT}:7878" 51 | - "${REALM_PORT}:8085" 52 | restart: unless-stopped 53 | 54 | phpmyadmin: 55 | image: phpmyadmin 56 | container_name: ${CONTAINER_NAME}-phpmyadmin 57 | ports: 58 | - "${PHPADMIN_PORT}:80" 59 | environment: 60 | - PMA_HOST=${DB_HOST} 61 | - PMA_PORT=${DB_PORT} 62 | - PMA_USER=${SERVER_DB_USER} 63 | - PMA_PASSWORD=${SERVER_DB_PASSWORD} 64 | restart: "no" 65 | profiles: 66 | - phpadmin 67 | 68 | db: 69 | image: mariadb:latest 70 | container_name: ${CONTAINER_NAME}-db 71 | environment: 72 | - TZ=${TIMEZONE} 73 | - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} 74 | command: --max_allowed_packet=67108864 75 | ports: 76 | - "${DB_PORT}:3306" 77 | restart: unless-stopped 78 | profiles: 79 | - db 80 | 81 | networks: 82 | default: 83 | name: ${CONTAINER_NAME}-network 84 | -------------------------------------------------------------------------------- /docker/utility/commands/configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "=== Configuring ${PROJECT_NAME} authserver and worldserver (overwrite mode) ===" 5 | 6 | # Ensure etc directory exists 7 | mkdir -p "$INSTALL_PREFIX/etc" 8 | 9 | # Always reset authserver.conf 10 | echo "Resetting authserver.conf..." 11 | cp "$INSTALL_PREFIX/etc/authserver.conf.dist" "$INSTALL_PREFIX/etc/authserver.conf" 12 | 13 | sed -i -e "s|^LogsDir =.*|LogsDir = \"$LOGS_DIR_PATH\"|" "$INSTALL_PREFIX/etc/authserver.conf" 14 | sed -i -e "s|^LoginDatabaseInfo =.*|LoginDatabaseInfo = \"$DB_HOST;$DB_PORT;$SERVER_DB_USER;$SERVER_DB_PASSWORD;$AUTH_DB\"|" "$INSTALL_PREFIX/etc/authserver.conf" 15 | 16 | # Always reset worldserver.conf 17 | echo "Resetting worldserver.conf..." 18 | cp "$INSTALL_PREFIX/etc/worldserver.conf.dist" "$INSTALL_PREFIX/etc/worldserver.conf" 19 | 20 | sed -i -e "s|^DataDir =.*|DataDir = \"$DATA_DIR_PATH\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 21 | sed -i -e "s|^LogsDir =.*|LogsDir = \"$LOGS_DIR_PATH\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 22 | 23 | sed -i -e "s|^LoginDatabaseInfo.*|LoginDatabaseInfo = \"$DB_HOST;$DB_PORT;$SERVER_DB_USER;$SERVER_DB_PASSWORD;$AUTH_DB\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 24 | sed -i -e "s|^WorldDatabaseInfo.*|WorldDatabaseInfo = \"$DB_HOST;$DB_PORT;$SERVER_DB_USER;$SERVER_DB_PASSWORD;$WORLD_DB\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 25 | sed -i -e "s|^CharacterDatabaseInfo.*|CharacterDatabaseInfo = \"$DB_HOST;$DB_PORT;$SERVER_DB_USER;$SERVER_DB_PASSWORD;$CHARACTER_DB\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 26 | 27 | sed -i -e "s|^GameType =.*|GameType = \"$GAME_TYPE\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 28 | sed -i -e "s|^RealmZone =.*|RealmZone = \"$REALM_ZONE\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 29 | sed -i -e "s|^Motd =.*|Motd = \"$MOTD_MSG\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 30 | 31 | sed -i -e "s|^Ra.Enable =.*|Ra.Enable = \"$RA_ENABLE\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 32 | sed -i -e "s|^SOAP.Enabled =.*|SOAP.Enabled = \"$SOAP_ENABLE\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 33 | sed -i -e "s|^SOAP.IP =.*|SOAP.IP = \"$SOAP_IP\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 34 | 35 | sed -i -e "s|^Console.Enable =.*|Console.Enable = \"$CONSOLE\"|" "$INSTALL_PREFIX/etc/worldserver.conf" 36 | 37 | echo "=== Configuration updated successfully ===" -------------------------------------------------------------------------------- /docker/utility/commands/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | 5 | 6 | # --- Default variables (overridable via .env) --- 7 | PROJECT_NAME="${PROJECT_NAME:-Pandaria}" 8 | INSTALL_PREFIX="${INSTALL_PREFIX:-/app}" 9 | SOURCE_PREFIX="${SOURCE_PREFIX:-/src/pandaria_5.4.8}" 10 | BUILD_DIR="$SOURCE_PREFIX/build" 11 | 12 | echo "=== Compiling Project $PROJECT_NAME ===" 13 | 14 | # Compiler defaults (from .env or fallback) 15 | CMAKE_C_COMPILER="${CMAKE_C_COMPILER:-/usr/bin/clang-14}" 16 | CMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER:-/usr/bin/clang++-14}" 17 | CMAKE_DISABLE_PCH="${CMAKE_DISABLE_PCH:-ON}" # Disable precompiled headers for stability 18 | BUILD_CORES="${BUILD_CORES:-0}" # 0 = all cores 19 | 20 | # Flags (can be overridden by CMAKE_CXX_FLAGS in .env) 21 | if [ -z "$CMAKE_CXX_FLAGS" ]; then 22 | CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo || true) 23 | BASE_FLAGS="-pthread -O2" 24 | 25 | # Lower optimization for older CPUs (Ivy Bridge and older) 26 | if echo "$CPU_MODEL" | grep -Eq "i[357]-[23]"; then 27 | echo "Old CPU detected ($CPU_MODEL). Disabling -march=native and lowering optimization..." 28 | CMAKE_CXX_FLAGS="-pthread -O1" 29 | else 30 | CMAKE_CXX_FLAGS="$BASE_FLAGS -march=native" 31 | fi 32 | fi 33 | 34 | export LDFLAGS="-Wl,--copy-dt-needed-entries" 35 | export CMAKE_CXX_FLAGS 36 | 37 | echo "Using compiler: $CMAKE_CXX_COMPILER" 38 | echo "C++ Flags: $CMAKE_CXX_FLAGS" 39 | echo "Project: $PROJECT_NAME" 40 | 41 | # --- Ensure runtime directories exist --- 42 | mkdir -p "$INSTALL_PREFIX/logs" "$INSTALL_PREFIX/etc" "$INSTALL_PREFIX/bin" "$INSTALL_PREFIX/sql" "$INSTALL_PREFIX/data" "$INSTALL_PREFIX/lib" 43 | mkdir -p "$BUILD_DIR" 44 | cd "$BUILD_DIR" 45 | 46 | # --- Run CMake --- 47 | cmake .. \ 48 | -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" \ 49 | -DCMAKE_C_COMPILER="$CMAKE_C_COMPILER" \ 50 | -DCMAKE_CXX_COMPILER="$CMAKE_CXX_COMPILER" \ 51 | -DSCRIPTS="${SCRIPTS:-ON}" \ 52 | -DWITH_WARNINGS="${WARNINGS:-OFF}" \ 53 | -DTOOLS="${EXTRACTORS:-ON}" \ 54 | -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \ 55 | -DCMAKE_DISABLE_PRECOMPILE_HEADERS="$CMAKE_DISABLE_PCH" \ 56 | -DACE_INCLUDE_DIR="${ACE_INCLUDE_DIR:-/usr/include}" \ 57 | -DACE_LIBRARY="${ACE_LIBRARY:-/usr/lib/x86_64-linux-gnu/libACE.so}" 58 | 59 | # --- Clean old build --- 60 | make clean 61 | 62 | # --- Build & install --- 63 | if [ "${MAKE_INSTALL:-1}" -eq 1 ]; then 64 | echo "Running make install..." 65 | TOTAL_CORES=$(nproc) 66 | if [ "$BUILD_CORES" -eq 0 ]; then 67 | CORES="$TOTAL_CORES" 68 | else 69 | CORES="$BUILD_CORES" 70 | fi 71 | 72 | echo "Using $CORES cores for build (System total: $TOTAL_CORES)" 73 | make -j"$CORES" install 74 | fi 75 | 76 | echo "=== Compile complete for $PROJECT_NAME ===" 77 | -------------------------------------------------------------------------------- /docker/utility/commands/exec_sql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Load environment (if not already loaded by container) 5 | if [ -f "$(dirname "$0")/.env" ]; then 6 | # shellcheck disable=SC1091 7 | . "$(dirname "$0")/.env" 8 | fi 9 | 10 | # Arguments 11 | SUBDIR="$1" # required (relative to /app/sql/, e.g., install, fixes, custom, templates) 12 | SQL_FILE="$2" # optional (specific SQL file to run) 13 | FORCE_DB="$3" # optional (explicit DB override: AUTH_DB, WORLD_DB, CHARACTER_DB) 14 | 15 | BASE_PATH="/app/sql" 16 | TARGET_DIR="$BASE_PATH/$SUBDIR" 17 | 18 | if [ ! -d "$TARGET_DIR" ]; then 19 | echo "Error: Directory $TARGET_DIR does not exist." 20 | exit 1 21 | fi 22 | 23 | # Decide which files to process 24 | if [ -n "$SQL_FILE" ]; then 25 | FILES="$TARGET_DIR/$SQL_FILE" 26 | [ -f "$FILES" ] || { echo "Error: File $FILES not found."; exit 1; } 27 | else 28 | FILES="$TARGET_DIR"/*.sql 29 | fi 30 | 31 | for FILE in $FILES; do 32 | [ -f "$FILE" ] || continue 33 | 34 | # Determine target DB if not overridden 35 | TARGET_DB="$FORCE_DB" 36 | if [ -z "$TARGET_DB" ]; then 37 | case "$(basename "$FILE")" in 38 | world_*) TARGET_DB="$WORLD_DB" ;; 39 | auth_*) TARGET_DB="$AUTH_DB" ;; 40 | characters_*) TARGET_DB="$CHARACTER_DB" ;; 41 | *) TARGET_DB="" ;; # Will run without selecting a DB 42 | esac 43 | fi 44 | 45 | # Substitute environment variables into temp file 46 | TMP_SQL=$(mktemp) 47 | cp "$FILE" "$TMP_SQL" 48 | 49 | VARS=$(grep -oE '\$\{[A-Za-z0-9_]+\}' "$TMP_SQL" | sort -u) 50 | for var in $VARS; do 51 | NAME=$(echo "$var" | sed 's/[${}]//g') 52 | VALUE=$(eval echo "\$$NAME") 53 | 54 | if [ -z "$VALUE" ]; then 55 | echo "Error: Variable $NAME is not set (required by $(basename "$FILE"))" 56 | rm -f "$TMP_SQL" 57 | continue 2 58 | fi 59 | 60 | ESCAPED=$(printf '%s\n' "$VALUE" | sed 's/[\/&]/\\&/g') 61 | sed -i "s|\${$NAME}|$ESCAPED|g" "$TMP_SQL" 62 | done 63 | 64 | echo "Executing $(basename "$FILE") on ${TARGET_DB:-no database}..." 65 | 66 | # Run MySQL with --force so the file continues even if some statements fail 67 | if [ -n "$TARGET_DB" ]; then 68 | mysql --force -h "$DB_HOST" -P "$DB_PORT" -u "$MYSQL_USERNAME" -p"$MYSQL_PASSWORD" "$TARGET_DB" < "$TMP_SQL" 69 | else 70 | mysql --force -h "$DB_HOST" -P "$DB_PORT" -u "$MYSQL_USERNAME" -p"$MYSQL_PASSWORD" < "$TMP_SQL" 71 | fi 72 | 73 | # MySQL will still return error code if any statement fails, but we log a warning and continue 74 | if [ $? -ne 0 ]; then 75 | echo "Warning: Errors occurred while running $(basename "$FILE"). Continuing..." 76 | fi 77 | 78 | rm -f "$TMP_SQL" 79 | echo "Done with $(basename "$FILE")." 80 | done 81 | -------------------------------------------------------------------------------- /env.dist: -------------------------------------------------------------------------------- 1 | # ====================== 2 | # Core & Project Info 3 | # ====================== 4 | PROJECT_NAME=Pandaria 5 | TIMEZONE=Europe/Stockholm 6 | WOW_LOCALE=enGB 7 | 8 | # ====================== 9 | # Paths & Directories 10 | # ====================== 11 | INSTALL_PREFIX=/app 12 | SOURCE_PREFIX=/src/pandaria_5.4.8 13 | 14 | DATA_DIR_PATH=/app/data 15 | LOGS_DIR_PATH=/app/logs 16 | ETC_DIR_PATH=/app/etc 17 | CUSTOM_DIR=/app/custom_conf 18 | 19 | SQL_INSTALL_DIR=app/sql/install 20 | SQL_UPDATES_DIR=/src/pandaria_5.4.8/sql/updates 21 | SQL_BASE_DIR=/src/pandaria_5.4.8/sql/base 22 | SQL_FIXES_DIR=/app/sql/fixes 23 | SQL_CUSTOM_DIR=/app/sql/custom 24 | 25 | WOW_PATH= 26 | WOW_INTERNAL=/app/wow 27 | 28 | START_AUTH=./bin/authserver 29 | START_WORLD=./bin/worldserver 30 | 31 | # ====================== 32 | # Docker & Container Config 33 | # ====================== 34 | EXTERNAL_DB=true 35 | CONTAINER_NAME=pandaria 36 | IMAGE_NAME=pandaria 37 | OS_NAME=debian12-slim 38 | 39 | # You can change which Debian release to use. 40 | # NOTE: If you switch to another distro (e.g. Ubuntu), 41 | # you must also adjust the package list 42 | BASE_IMAGE=debian:bookworm-slim 43 | 44 | AUTH_PORT=3724 45 | REALM_ADDRESS=192.168.1.30 46 | REALM_PORT=8085 47 | RA_PORT=3443 48 | SOAP_PORT=7878 49 | PHPADMIN_PORT=8080 50 | 51 | # ====================== 52 | # Build & Compilation 53 | # ====================== 54 | CMAKE_C_COMPILER=/usr/bin/clang-14 55 | CMAKE_CXX_COMPILER=/usr/bin/clang++-14 56 | 57 | # Default flags (may cause issues on old CPUs) 58 | CMAKE_CXX_FLAGS=-pthread 59 | 60 | # Stable fallback flags (uncomment if builds crash) 61 | # CMAKE_CXX_FLAGS=-O0 -g -pthread -fno-strict-aliasing -fno-pch 62 | 63 | BUILD_CORES=0 64 | CMAKE_DISABLE_PCH=OFF 65 | SCRIPTS=static 66 | WARNINGS=0 67 | EXTRACTORS=1 68 | MAKE_INSTALL=1 69 | 70 | ACE_INCLUDE_DIR=/usr/include 71 | ACE_LIBRARY=/usr/lib/x86_64-linux-gnu/libACE.so 72 | 73 | # ====================== 74 | # Database & Credentials 75 | # ====================== 76 | DB_CONTAINER=mysql 77 | DB_HOST=192.168.11.30 78 | DB_PORT=3306 79 | 80 | MYSQL_USERNAME=root 81 | MYSQL_PASSWORD=pwd 82 | 83 | SERVER_DB_USER=pandaria 84 | SERVER_DB_PASSWORD=pwd 85 | 86 | AUTH_DB=pandaria548_auth 87 | WORLD_DB=pandaria548_world 88 | CHARACTER_DB=pandaria548_characters 89 | 90 | # ====================== 91 | # SQL Source & Bundling 92 | # ====================== 93 | AUTH_SQL=auth_04_03_2023.sql 94 | CHARACTER_SQL=characters_29_12_2024.sql 95 | WORLD_SQL=world_04_03_2023.sql 96 | 97 | REPO_URL=https://github.com/alexkulya/pandaria_5.4.8.git 98 | WORLD_DB_URL=https://github.com/alexkulya/pandaria_5.4.8/releases/download/%23pandaria548world/2024_08_01_world.zip 99 | WORLD_DB_ZIP=/app/sql/install/latest_world.zip 100 | WORLD_SQL_UPDATE=/app/sql/install/2024_08_01_world.sql 101 | 102 | # ====================== 103 | # Data Extraction Options 104 | # ====================== 105 | MAPS=ON 106 | VMAPS=ON 107 | MMAPS=ON 108 | 109 | # ====================== 110 | # Worldserver Configuration 111 | # ====================== 112 | GAME_TYPE=0 113 | REALM_ZONE=1 114 | MOTD_MSG="Welcome to Pandaria 5.4.8" 115 | 116 | REALM_NAME=Pandaria 5.4.8 117 | REALM_ICON=1 118 | REALM_COLOR=0 119 | REALM_TIMEZONE=1 120 | REALM_SECURITY=0 121 | REALM_POP=0 122 | REALM_BUILD=18414 123 | REALM_FLAG=0 124 | 125 | RA_ENABLE=1 126 | SOAP_ENABLE=0 127 | SOAP_IP=0.0.0.0 128 | CONSOLE=0 129 | -------------------------------------------------------------------------------- /docker/utility/commands/build_sql_bundles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # --- Default variables (can be overridden in .env) --- 5 | PROJECT_NAME="${PROJECT_NAME:-Pandaria}" 6 | 7 | SQL_INSTALL_DIR="${SQL_INSTALL_DIR:-/app/sql/install}" 8 | SQL_TMP_DIR="$SQL_INSTALL_DIR/tmp" 9 | SQL_UPDATES_DIR="${SQL_UPDATES_DIR:-/src/pandaria_5.4.8/sql/updates}" 10 | SQL_BASE_DIR="${SQL_BASE_DIR:-/src/pandaria_5.4.8/sql/base}" 11 | 12 | # These filenames must exist in the extracted zips 13 | AUTH_SQL="${AUTH_SQL:-auth_04_03_2023.sql}" 14 | CHARACTER_SQL="${CHARACTER_SQL:-characters_29_12_2024.sql}" 15 | WORLD_SQL="${WORLD_SQL:-world_04_03_2023.sql}" 16 | 17 | # Output bundle files (always generated with these names) 18 | AUTH_BUNDLE="$SQL_INSTALL_DIR/auth_base.sql" 19 | CHAR_BUNDLE="$SQL_INSTALL_DIR/characters_base.sql" 20 | WORLD_BUNDLE="$SQL_INSTALL_DIR/world_base.sql" 21 | WORLD_UPDATE="$SQL_INSTALL_DIR/world_update.sql" 22 | 23 | AUTH_PATCHES="$SQL_INSTALL_DIR/auth_patches_update.sql" 24 | CHAR_PATCHES="$SQL_INSTALL_DIR/characters_patches_update.sql" 25 | WORLD_PATCHES="$SQL_INSTALL_DIR/world_patches_update.sql" 26 | 27 | # --- Prepare directories --- 28 | mkdir -p "$SQL_INSTALL_DIR" "$SQL_TMP_DIR" 29 | rm -f "$SQL_INSTALL_DIR"/*.sql 30 | 31 | echo "=== Building bundled SQL files for $PROJECT_NAME ===" 32 | 33 | # --- Extract base SQL from zips --- 34 | echo "Unzipping base databases..." 35 | unzip -o "$SQL_BASE_DIR/auth_*.zip" -d "$SQL_TMP_DIR" 36 | unzip -o "$SQL_BASE_DIR/characters_*.zip" -d "$SQL_TMP_DIR" 37 | unzip -o "$SQL_BASE_DIR/world_*.zip" -d "$SQL_TMP_DIR" 38 | 39 | # Move/rename base SQL to consistent names 40 | mv -f "$SQL_TMP_DIR/$AUTH_SQL" "$AUTH_BUNDLE" 41 | mv -f "$SQL_TMP_DIR/$CHARACTER_SQL" "$CHAR_BUNDLE" 42 | mv -f "$SQL_TMP_DIR/$WORLD_SQL" "$WORLD_BUNDLE" 43 | 44 | # --- Find and prepare latest world update --- 45 | LATEST_WORLD_ZIP=$(find "$SQL_INSTALL_DIR" -maxdepth 1 -type f -name '*.zip' 2>/dev/null | head -n1) 46 | 47 | if [ -z "$LATEST_WORLD_ZIP" ]; then 48 | echo "Downloading latest world dump..." 49 | [ -z "$WORLD_DB_URL" ] && { echo "Error: WORLD_DB_URL is not set."; exit 1; } 50 | LATEST_WORLD_ZIP="$SQL_INSTALL_DIR/latest_world.zip" 51 | wget --progress=bar:force:noscroll "$WORLD_DB_URL" -O "$LATEST_WORLD_ZIP" 52 | fi 53 | 54 | echo "Extracting latest world update..." 55 | unzip -o "$LATEST_WORLD_ZIP" -d "$SQL_TMP_DIR" 56 | 57 | LATEST_WORLD_SQL=$(find "$SQL_TMP_DIR" -maxdepth 1 -type f -name '*.sql' | head -n1) 58 | if [ -z "$LATEST_WORLD_SQL" ]; then 59 | echo "Error: No SQL file found inside $LATEST_WORLD_ZIP." 60 | exit 1 61 | fi 62 | mv -f "$LATEST_WORLD_SQL" "$WORLD_UPDATE" 63 | 64 | # --- Merge incremental patches --- 65 | merge_patches() { 66 | local src_dir="$1" 67 | local target="$2" 68 | 69 | if [ ! -d "$src_dir" ]; then 70 | echo "No patches in $src_dir, skipping." 71 | return 72 | fi 73 | 74 | echo "Merging patches from $src_dir into $target..." 75 | cat $(find "$src_dir" -type f -name '*.sql' | sort) > "$target" || echo "-- No patches merged" > "$target" 76 | } 77 | 78 | merge_patches "$SQL_UPDATES_DIR/auth" "$AUTH_PATCHES" 79 | merge_patches "$SQL_UPDATES_DIR/characters" "$CHAR_PATCHES" 80 | merge_patches "$SQL_UPDATES_DIR/world" "$WORLD_PATCHES" 81 | 82 | # --- Normalize DB names in all SQL files --- 83 | echo "Normalizing database names..." 84 | for file in "$SQL_INSTALL_DIR"/*.sql; do 85 | [ -f "$file" ] || continue 86 | echo "Patching $file..." 87 | sed -i -E "s/(CREATE DATABASE.*|USE) *\`auth\`/\1 \`$AUTH_DB\`/Ig" "$file" 88 | sed -i -E "s/(CREATE DATABASE.*|USE) *\`characters\`/\1 \`$CHARACTER_DB\`/Ig" "$file" 89 | sed -i -E "s/(CREATE DATABASE.*|USE) *\`world\`/\1 \`$WORLD_DB\`/Ig" "$file" 90 | done 91 | 92 | # --- Cleanup --- 93 | rm -rf "$SQL_TMP_DIR" 94 | 95 | echo "=== All bundled SQL files for $PROJECT_NAME are ready in $SQL_INSTALL_DIR ===" 96 | ls -1 "$SQL_INSTALL_DIR"/*.sql || echo "(No files generated)" 97 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for $(PROJECT_NAME) 5.4.8 Utility 2 | MAKEFLAGS += --silent 3 | 4 | # --- Load environment variables --- 5 | ifneq ("$(wildcard .env)","") 6 | include .env 7 | export $(shell sed -n 's/^\([^#]\+\)=.*/\$(EXTRACTORS)/p' .env) 8 | endif 9 | 10 | DOCKER_COMPOSE := docker compose 11 | UTILITY := utility 12 | 13 | # Telnet defaults (can override in .env) 14 | TELNET_HOST ?= $(REALM_ADDRESS) 15 | TELNET_PORT ?= $(RA_PORT) 16 | 17 | # DB container profile (only runs if EXTERNAL_DB=false) 18 | DB_PROFILES := 19 | DB_MODE=external 20 | DB_SERVICE= 21 | ifeq ($(EXTERNAL_DB),false) 22 | DB_PROFILES := --profile db 23 | DB_MODE=internal 24 | DB_SERVICE=db 25 | endif 26 | 27 | .DEFAULT_GOAL := help 28 | 29 | help: 30 | @echo "Available commands:" 31 | @echo "" 32 | @echo "=== Build & Setup ===" 33 | @echo " make fetch_source - Clone or update the $(PROJECT_NAME) source code" 34 | @echo " make build - Build the utility container" 35 | @echo " make build-nocache - Build the utility container without cache" 36 | @echo " make compile - Compile the server (SkyFire/$(PROJECT_NAME))" 37 | @echo " make configure - Generate fresh authserver/worldserver configs" 38 | @echo " make extract_data - Extract maps, vmaps, and mmaps from client" 39 | @echo " make install - Full installation (build, extract, DB, start servers)" 40 | @echo "" 41 | @echo "=== Database Management ===" 42 | @echo " make setup_db - Initialize, bundle, install, and finalize all databases" 43 | @echo " make bundle_db - Build SQL bundles (base, patches, fixes, custom) into $(SQL_INSTALL_DIR)" 44 | @echo " make init_db - Drop and recreate MySQL/MariaDB databases" 45 | @echo " make populate_db - Install base SQL Gfiles from $(SQL_INSTALL_DIR)" 46 | @echo " make update_db - Apply patch SQL bundles from $(SQL_INSTALL_DIR)" 47 | @echo " make fix_db - Apply SQL fixes (bundled per DB) from $(SQL_INSTALL_DIR)" 48 | @echo " make add_custom_db - Apply custom SQL (bundled per DB) from $(SQL_INSTALL_DIR)" 49 | @echo " make finalize_db - Update auth DB with accounts and realm info" 50 | @echo " make backup_db - Backup all $(PROJECT_NAME) databases" 51 | @echo " make restore_db - Restore all $(PROJECT_NAME) databases" 52 | @echo " make apply_sql - Run SQL manually (DIR=, FILE=, DB=)" 53 | @echo "" 54 | @echo "=== Server Operations ===" 55 | @echo " make start - Start all containers (DB included unless EXTERNAL_DB=$(EXTERNAL_DB))" 56 | @echo " make stop - Stop all containers" 57 | @echo " make restart - Restart all containers" 58 | @echo " make logs - Follow container logs" 59 | @echo " make telnet - Connect to the RA console via telnet" 60 | @echo "" 61 | @echo "=== Config & Client ===" 62 | @echo " make configure_client - Update client realmlist and Config.wtf" 63 | @echo " make apply_custom_config - Apply .conf overrides from $(CUSTOM_DIR)" 64 | @echo "" 65 | @echo "=== Cleanup & Debug ===" 66 | @echo " make down - Stop and remove all containers (volumes kept)" 67 | @echo " make uninstall - Remove containers, volumes, DB, and images" 68 | @echo " make clean - Remove dangling Docker images" 69 | @echo " make shell - Open a shell in the utility container" 70 | @echo " make check - Verify required dependencies" 71 | 72 | # --- Build & Compile --- 73 | build: 74 | $(DOCKER_COMPOSE) build $(UTILITY) 75 | 76 | build-nocache: 77 | $(DOCKER_COMPOSE) build --no-cache $(UTILITY) 78 | 79 | compile: 80 | $(DOCKER_COMPOSE) run --rm $(UTILITY) compile 81 | 82 | configure: 83 | $(DOCKER_COMPOSE) run --rm $(UTILITY) configure 84 | 85 | extract_data: 86 | $(DOCKER_COMPOSE) run --rm $(UTILITY) extract_data 87 | 88 | # --- Database Operations --- 89 | init_db: 90 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh templates init_db_template.sql 91 | 92 | populate_db: 93 | @echo "Installing base SQL files..." 94 | @if ls $(SQL_INSTALL_DIR)/*_base.sql >/dev/null 2>&$(EXTRACTORS); then \ 95 | for f in $(SQL_INSTALL_DIR)/*_base.sql; do \ 96 | echo "Applying $$f..."; \ 97 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh install "$$(basename $$f)" || \ 98 | echo "Warning: Failed to apply $$f (continuing)"; \ 99 | done; \ 100 | else \ 101 | echo "Warning: No base SQL found. Run 'make bundle_db' first."; \ 102 | fi 103 | 104 | update_db: 105 | @echo "Applying SQL patch bundles..." 106 | @if ls $(SQL_INSTALL_DIR)/*_patches_update.sql >/dev/null 2>&$(EXTRACTORS); then \ 107 | for f in $(SQL_INSTALL_DIR)/*_patches_update.sql; do \ 108 | echo "Applying $$f..."; \ 109 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh install "$$(basename $$f)" || \ 110 | echo "Warning: Failed to apply $$f (continuing)"; \ 111 | done; \ 112 | else \ 113 | echo "Warning: No patch bundles found. Run 'make bundle_db' first."; \ 114 | fi 115 | 116 | fix_db: 117 | @echo "Applying SQL fixes..." 118 | @if ls $(SQL_INSTALL_DIR)/*_fixes.sql >/dev/null 2>&$(EXTRACTORS); then \ 119 | for f in $(SQL_INSTALL_DIR)/*_fixes.sql; do \ 120 | echo "Applying $$f..."; \ 121 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh install "$$(basename $$f)" || \ 122 | echo "Warning: Failed to apply $$f (continuing)"; \ 123 | done; \ 124 | else \ 125 | echo "Warning: No fix bundles found. Run 'make bundle_db' first."; \ 126 | fi 127 | 128 | add_custom_db: 129 | @echo "Applying custom SQL..." 130 | @if ls $(SQL_INSTALL_DIR)/*_custom.sql >/dev/null 2>&$(EXTRACTORS); then \ 131 | for f in $(SQL_INSTALL_DIR)/*_custom.sql; do \ 132 | echo "Applying $$f..."; \ 133 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh install "$$(basename $$f)" || \ 134 | echo "Warning: Failed to apply $$f (continuing)"; \ 135 | done; \ 136 | else \ 137 | echo "Warning: No custom bundles found. Run 'make bundle_db' first."; \ 138 | fi 139 | 140 | finalize_db: 141 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh templates auth_update_template.sql 142 | 143 | setup_db: 144 | @if [ "$(EXTERNAL_DB)" = "false" ]; then \ 145 | $(DOCKER_COMPOSE) up -d db; \ 146 | echo "Waiting 11 seconds for MySQL on $(DB_HOST) to start..."; \ 147 | sleep 11; \ 148 | fi 149 | 150 | @echo "Initializing databases..." 151 | $(MAKE) init_db 152 | @echo "Bundling SQL files..." 153 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/build_sql_bundles.sh 154 | @echo "Installing all SQL files..." 155 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/install_all_sql.sh 156 | @echo "Finalizing auth DB..." 157 | $(MAKE) finalize_db 158 | @echo "Database setup complete." 159 | 160 | backup_db: 161 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/backup_db.sh 162 | 163 | restore_db: 164 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/restore_db.sh 165 | 166 | bundle_db: 167 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/build_sql_bundles.sh 168 | 169 | 170 | DIR ?= misc 171 | FILE ?= 172 | DB ?= 173 | 174 | apply_sql: 175 | @if [ -n "$(FILE)" ]; then \ 176 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh "$(DIR)" "$(FILE)" "$(DB)"; \ 177 | else \ 178 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh "$(DIR)" "" "$(DB)"; \ 179 | fi 180 | 181 | start: 182 | @echo "Starting services (DB: $(DB_MODE))" 183 | @if [ "$(EXTERNAL_DB)" = "false" ]; then \ 184 | $(DOCKER_COMPOSE) up -d db authserver worldserver; \ 185 | else \ 186 | $(DOCKER_COMPOSE) up -d authserver worldserver; \ 187 | fi 188 | 189 | stop: 190 | @echo "Stopping services (DB: $(DB_MODE))" 191 | @if [ "$(EXTERNAL_DB)" = "false" ]; then \ 192 | $(DOCKER_COMPOSE) stop db authserver worldserver; \ 193 | else \ 194 | $(DOCKER_COMPOSE) stop authserver worldserver; \ 195 | fi 196 | 197 | restart: 198 | @echo "Restarting services (DB: $(DB_MODE))" 199 | @if [ "$(EXTERNAL_DB)" = "false" ]; then \ 200 | $(DOCKER_COMPOSE) restart db authserver worldserver; \ 201 | else \ 202 | $(DOCKER_COMPOSE) restart authserver worldserver; \ 203 | fi 204 | 205 | logs: 206 | @echo "Tailing logs (DB: $(DB_MODE))" 207 | @if [ "$(EXTERNAL_DB)" = "false" ]; then \ 208 | $(DOCKER_COMPOSE) logs -f db authserver worldserver; \ 209 | else \ 210 | $(DOCKER_COMPOSE) logs -f authserver worldserver; \ 211 | fi 212 | 213 | down: 214 | @echo "Removing services (DB: $(DB_MODE))" 215 | @if [ "$(EXTERNAL_DB)" = "false" ]; then \ 216 | $(DOCKER_COMPOSE) down db authserver worldserver; \ 217 | else \ 218 | $(DOCKER_COMPOSE) down authserver worldserver; \ 219 | fi 220 | 221 | uninstall: 222 | @echo "Removing all containers, volumes, and images..." 223 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands/exec_sql.sh templates uninstall_db_template.sql 224 | $(DOCKER_COMPOSE) down -v --rmi all --remove-orphans 225 | docker system prune -af 226 | 227 | # --- Utilities --- 228 | shell: 229 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/bash 230 | 231 | clean: 232 | docker image prune -f 233 | 234 | telnet: 235 | @echo "Connecting to RA console at $(TELNET_HOST):$(TELNET_PORT)..." 236 | @telnet $(TELNET_HOST) $(TELNET_PORT) 237 | 238 | configure_client: 239 | @sh misc/configure_client.sh '$(WOW_PATH)' '$(WOW_LOCALE)' '$(REALM_ADDRESS)' 240 | 241 | apply_custom_config: 242 | $(DOCKER_COMPOSE) run --rm $(UTILITY) /bin/commands$(INSTALL_PREFIX) apply_custom_config.sh $(FILE) 243 | 244 | install: fetch_source build compile extract_data setup_db configure start 245 | @echo "Installation complete. All services are running." 246 | 247 | # --- Dependency Check --- 248 | check: 249 | @echo "Checking required dependencies..." 250 | @if ! command -v docker >/dev/null 2>&$(EXTRACTORS); then \ 251 | echo "Error: docker is not installed."; exit $(EXTRACTORS); \ 252 | fi 253 | @if ! docker compose version >/dev/null 2>&$(EXTRACTORS); then \ 254 | echo "Error: docker compose is missing."; exit $(EXTRACTORS); \ 255 | fi 256 | @if ! command -v git >/dev/null 2>&$(EXTRACTORS); then \ 257 | echo "Error: git is not installed."; exit $(EXTRACTORS); \ 258 | fi 259 | @if ! command -v telnet >/dev/null 2>&$(EXTRACTORS); then \ 260 | echo "Error: telnet is not installed."; exit $(EXTRACTORS); \ 261 | fi 262 | @echo "All dependencies are present." 263 | 264 | fetch_source: 265 | @if [ ! -d src/pandaria_5.4.8 ]; then \ 266 | echo "Cloning $(PROJECT_NAME) source..."; \ 267 | mkdir -p src; \ 268 | git clone $(REPO_URL) src/pandaria_5.4.8; \ 269 | else \ 270 | echo "Updating $(PROJECT_NAME) source..."; \ 271 | cd src/pandaria_5.4.8; \ 272 | git pull --rebase; \ 273 | fi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pandaria 5.4.8 – Dockerized Server 2 | 3 | ## Overview 4 | 5 | This project provides a **Docker-based setup** for Pandaria 5.4.8, intended as a **learning tool** for containerized game servers. 6 | It is not designed for public hosting or production use but offers a quick way to build, configure, and run Pandaria 5.4.8 locally. 7 | 8 | --- 9 | 10 | ## Purpose 11 | 12 | With this project, you can: 13 | - Quickly build and run a Pandaria 5.4.8 server without manual dependency management. 14 | - Experiment with SQL tweaks, custom content, and server configurations. 15 | - Learn Docker workflows for multi-service setups. 16 | 17 | This is primarily for **personal use, testing, and education**, not for commercial or large-scale deployment. 18 | 19 | --- 20 | 21 | ## Key Features 22 | - Automated **compilation and database setup** with `make`. 23 | - Support for **internal MariaDB** or **external database connections**. 24 | - Modular services: each component (authserver, worldserver, database, phpMyAdmin, utilities) runs in its own container. 25 | - Tools for **client configuration**, backups, and applying custom SQL or configuration overrides. 26 | - Customization via `/app/custom_sql` and `/app/custom_conf`. 27 | 28 | This setup is tested on **Linux hosts** with Docker and Docker Compose. 29 | Windows and macOS are supported but may require manual tweaks, especially for MariaDB and file paths. 30 | 31 | --- 32 | 33 | ## Client Preparation 34 | 35 | Before starting the server, your **World of Warcraft: Mists of Pandaria client (5.4.8)** must be patched to connect properly. 36 | Follow the instructions provided by the SkyFire or Pandaria 5.4.8 project for your client version. 37 | Without proper patching, the client may not connect or may behave unpredictably. 38 | 39 | --- 40 | 41 | ## Limitations 42 | 43 | - Intended for **private, educational use only**. 44 | - Not optimized for **public or production servers**. 45 | 46 | --- 47 | 48 | ## Quick Installation Guide (Linux) 49 | 50 | ### 1. Prerequisites 51 | Ensure the following are installed: 52 | - Docker 53 | - Docker Compose 54 | - Git 55 | - Telnet client 56 | 57 | Install them using your distribution’s package manager (e.g., `apt`, `dnf`, or `pacman`). 58 | 59 | --- 60 | 61 | ### 2. Environment Setup 62 | Copy the example `.env` file and configure it: 63 | ```bash 64 | cp env.dist .env 65 | ``` 66 | 67 | Edit .env to set: 68 | • REALM_ADDRESS – your server IP or hostname 69 | • WOW_PATH – path to your MoP 5.4.8 client 70 | • Database settings – set EXTERNAL_DB=true if you want to use an existing database; otherwise, the internal MariaDB container will be used. 71 | 72 | 73 | ### 3. Install and Run the Server 74 | 75 | ```bash 76 | make install 77 | ```` 78 | 79 | This command will: 80 | 1. Fetch or update the source code. 81 | 2. Build all Docker containers (utility, authserver, worldserver, database if internal). 82 | 3. Compile the Pandaria 5.4.8 server. 83 | 4. Extract maps, DBC, VMaps, and MMaps into /app/data. 84 | 5. Initialize and configure the database. 85 | 6. Generate worldserver.conf and authserver.conf. 86 | 7. Start all services automatically. 87 | 88 | ### 4. Configure the WoW Client 89 | 90 | ```bash 91 | make configure_client 92 | ```` 93 | 94 | This will automatically update: 95 | • realmlist.wtf 96 | • Config.wtf 97 | 98 | ### 5. Log In and Play 99 | 100 | Use the default administrator account (GM Level 3 – full privileges): 101 | ```bash 102 | Username: admin 103 | Password: admin 104 | ``` 105 | 106 | ### 6. Creating Additional Accounts 107 | 108 | Use the built-in Remote Administration (RA) console via Telnet, logged in as the **default admin account** (GM Level 3): 109 | 110 | ```bash 111 | make telnet 112 | ``` 113 | 114 | This will connect to the RA console using REALM_ADDRESS and RA_PORT from your .env. 115 | Log in with: admin pass: admion 116 | 117 | 118 | ```bash 119 | account create 120 | account set gmlevel 121 | ``` 122 | 123 | GmLevels 124 | • 1 = Normal player (default access) 125 | • 3 = Highest GM privileges 126 | 127 | RealmID 128 | • The last argument is the realmID. 129 | • By default, the primary realm uses ID 1. 130 | • Use -1 to apply the same GM permission across all realms. 131 | 132 | ## Manual Setup (without make install) 133 | 134 | If you prefer to run each step manually, you can use the underlying Docker Compose commands directly 135 | 136 | ```bash 137 | # 1. Build the utility container (compiles SkyFire and provides tools) 138 | docker compose build utility 139 | 140 | # 2. Compile the Pandaria 5.4.8 core 141 | docker compose run --rm utility compile 142 | 143 | # 3. Extract maps, DBC, VMaps, and MMaps 144 | docker compose run --rm utility extract_data 145 | 146 | # 4. Initialize and populate the database 147 | docker compose run --rm utility init_db 148 | docker compose run --rm utility populate_db 149 | docker compose run --rm utility update_db 150 | docker compose run --rm utility finalize_db 151 | 152 | # 5. Generate configuration files 153 | docker compose run --rm utility configure 154 | 155 | # 6. Start the servers (authserver, worldserver, and database if internal) 156 | docker compose up -d 157 | 158 | # 7. Follow the logs 159 | docker compose logs -f 160 | ``` 161 | 162 | 163 | 164 | ## Directory Overview 165 | 166 | This project uses several directories to organize source code, configuration, and runtime data. 167 | Below is an overview of each important directory and its purpose. Once connected, you can create accounts with: 168 | 169 | 170 | ## Directory Overview 171 | 172 | | Directory | Purpose | 173 | |------------------------------------|-------------------------------------------------------------------------| 174 | | `app/bin` | Compiled binaries (e.g., `authserver`, `worldserver`, and data tools). | 175 | | `app/custom_conf` | User-provided configuration overrides, merged after defaults. | 176 | | `app/data` | Extracted game data (maps, DBC, VMaps, MMaps) used by the servers. | 177 | | `app/etc` | Default configuration files for the servers (`authserver.conf`, etc.). | 178 | | `app/lib` | Libraries required by the server binaries (if not system-installed). | 179 | | `app/logs` | Log files from `authserver`, `worldserver`, and other services. | 180 | | `app/sql/backup` | Database backups (full or partial exports). | 181 | | `app/sql/custom` | Custom SQL scripts applied **after** all updates (for mounts, tweaks). | 182 | | `app/sql/fixes` | Fix scripts run **after DB updates but before minor patches**. | 183 | | `app/sql/install` | Base database installation scripts for auth/world/characters DBs. | 184 | | `app/sql/misc` | SQL scripts not applied automatically (manual tweaks or experiments). | 185 | | `app/sql/templates` | Template SQL files for custom database structures or test realms. | 186 | | `app/wow` | Local copy of the MoP 5.4.8 client (used for data extraction). | 187 | | `docker/authserver` | Dockerfile and configs for building the `authserver` container. | 188 | | `docker/utility` | Dockerfile and build environment for compiling, tools, and data tasks. | 189 | | `docker/worldserver` | Dockerfile and configs for building the `worldserver` container. | 190 | | `misc` | Helper scripts (client configurators, tools, maintenance). | 191 | | `src` | Source code for the Pandaria 5.4.8 core and its dependencies. | 192 | 193 | 194 | ## SQL Execution Order 195 | 196 | During `make install` and database initialization, SQL scripts from `/app/sql` are executed in the following order: 197 | 198 | 1. **`install/`** – Base schema and data for the `auth`, `characters`, and `world` databases. 199 | 2. **Official updates** – Incremental updates from the core repository. 200 | 3. **`fixes/`** – Custom fixes applied **after official updates but before final adjustments** (e.g., bug fixes, structural corrections). 201 | 4. **`custom/`** – Custom gameplay changes (mounts, vendors, rates) applied **last**, after all updates and fixes. 202 | 5. **`misc/`** – Not run automatically. Use for manual tweaks or experiments: 203 | 6. **`backup/`** – Contains database dumps for rollback or migration, not executed automatically. 204 | 7. **`templates/`** – Provides base structures or sample realms; not applied unless explicitly called. 205 | 206 | This order ensures: 207 | • The database is built from a clean state. 208 | • Official updates are always applied first. 209 | • Fixes and customizations never conflict with core updates. 210 | • Experimental SQL stays separate until explicitly executed. 211 | 212 | 213 | ## Applying Custom SQL and Config Files 214 | 215 | You can manually run SQL scripts or apply configuration overrides without re-running the full installation. 216 | **Note:** After applying SQL or configuration changes, you must restart `worldserver` (and `authserver` if configs were updated) for the changes to take effect. 217 | 218 | 219 | ### Running SQL Scripts 220 | 221 | The `make apply_sql` target executes SQL files against the chosen database. 222 | Usage: 223 | ```bash 224 | make apply_sql [FILE=] [DB=] 225 | ``` 226 | 227 | Parameters: 228 | • – One of the SQL directories under /app/sql (misc, custom, fixes, etc.). 229 | • FILE – (Optional) The SQL file to run. If omitted, all files in the directory will be applied. 230 | • DB – (Optional) Target database (auth, characters, or world). 231 | • If omitted, the system attempts to infer the target DB from the file name (e.g., auth_*.sql → auth DB). 232 | 233 | ```bash 234 | # Apply a single SQL file to the inferred database 235 | make apply_sql misc FILE=my_script.sql 236 | 237 | # Apply a single file to a specific database 238 | make apply_sql custom FILE=my_custom_world.sql DB=world 239 | 240 | # Apply all SQL files in the fixes directory 241 | make apply_sql fixes 242 | ``` 243 | 244 | 245 | ### Applying Custom Config Overrides 246 | 247 | ```bash 248 | make apply_custom_config [FILE=] 249 | ``` 250 | 251 | Parameters: 252 | • FILE – (Optional) Apply a single configuration file. 253 | • If omitted, all files in /app/custom_conf will be applied. 254 | 255 | 256 | ```bash 257 | # Apply all configuration overrides 258 | make apply_custom_config 259 | 260 | # Apply only a specific override 261 | make apply_custom_config FILE=worldserver.conf 262 | ``` 263 | 264 | Reminder: After applying configuration overrides, restart worldserver (and authserver if affected) for the new settings to load. 265 | 266 | 267 | 268 | ### Notes: 269 | - Files like `.keep` are used to preserve empty directories in Git but have no functional purpose. 270 | - Most directories (`/app/sql`, `/app/data`, `/src`, `/backup`) are ignored by Git except for `.keep` markers and specific custom folders. 271 | - SQL scripts in `custom_sql/fixes` and `custom_sql/custom` are run automatically during `make setup_db`. 272 | Scripts in `custom_sql/misc` **must be run manually** if needed. 273 | 274 | ### Disclaimer 275 | 276 | This project is **intended solely for private exploration and learning purposes**. 277 | It is not designed or supported for public hosting, commercial use, or as a production-grade server. 278 | The goal is to help users learn about Docker, experiment with Pandaria 5.4.8, and explore custom server configurations in a controlled, private environment. --------------------------------------------------------------------------------