upstream branch configs and docs

This commit is contained in:
uprightbass360
2025-10-25 18:57:16 -04:00
parent 51bc555dc0
commit ab7b982d9b
7 changed files with 577 additions and 312 deletions

View File

@@ -52,6 +52,13 @@ AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev
AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot
AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot
# =====================
# Services (Module Build Tags)
# =====================
# Images used during module compilation and tagging
AC_AUTHSERVER_IMAGE_MODULES=uprightbass360/azerothcore-wotlk-playerbots:authserver-modules-latest
AC_WORLDSERVER_IMAGE_MODULES=uprightbass360/azerothcore-wotlk-playerbots:worldserver-modules-latest
# ===================== # =====================
# Client Data # Client Data
# ===================== # =====================

View File

@@ -27,6 +27,8 @@ cd acore-compose
./deploy.sh ./deploy.sh
``` ```
> **Image Sources:** Vanilla/standard profiles run the upstream `acore/*` images. As soon as you enable playerbots or any C++ module, the toolchain switches to the `uprightbass360/azerothcore-wotlk-playerbots` fork, rebuilds it locally when needed, and produces fresh `uprightbass360/...:modules-latest` tags.
**4. Create Admin Account** **4. Create Admin Account**
Once the worldserver is running: Once the worldserver is running:
@@ -81,7 +83,7 @@ set realmlist 203.0.113.100 8215
### ✅ Core Server Components ### ✅ Core Server Components
- **AzerothCore 3.3.5a** - WotLK server application - **AzerothCore 3.3.5a** - WotLK server application
- **MySQL 8.0** - Database with intelligent initialization and restoration - **MySQL 8.0** - Database with intelligent initialization and restoration
- **Smart Module System** - Automated module management and source builds - **Smart Module System** - Automated module management and source builds (compiles the uprightbass360 playerbot fork whenever modules need C++ changes)
- **phpMyAdmin** - Web-based database administration - **phpMyAdmin** - Web-based database administration
- **Keira3** - Game content editor and developer tools - **Keira3** - Game content editor and developer tools
@@ -207,7 +209,7 @@ Use this workflow to build locally, then push the same stack to a remote host:
--host docker-server \ --host docker-server \
--project-dir /home/sam/src/acore-compose --project-dir /home/sam/src/acore-compose
``` ```
Adjust `--project-dir` (and `--identity`) to match your environment. The script copies the repo, `storage/`, and the `modules-latest` images to the remote machine. Adjust `--project-dir` (and `--identity`) to match your environment. The script copies the repo, `storage/`, and the `uprightbass360/...:modules-latest` images to the remote machine.
3. **Deploy Remotely** 3. **Deploy Remotely**
```bash ```bash
@@ -216,7 +218,7 @@ Use this workflow to build locally, then push the same stack to a remote host:
./deploy.sh --skip-rebuild --no-watch ./deploy.sh --skip-rebuild --no-watch
' '
``` ```
Because the `.env` now points the playerbot services at the `modules-latest` tags, the remote compose run uses the build you just migrated—no additional rebuild required. Because the `.env` now points the modules profile at the `uprightbass360/...:modules-latest` tags, the remote compose run uses the build you just migrated—no additional rebuild required.
4. **Verify** 4. **Verify**
```bash ```bash
@@ -237,7 +239,7 @@ Use this workflow to build locally, then push the same stack to a remote host:
--user sam \ --user sam \
--project-dir /home/sam/src/acore-compose --project-dir /home/sam/src/acore-compose
``` ```
(Exports rebuilt images to `local-storage/images/acore-modules-images.tar`, including both `acore/...:modules-latest` and `uprightbass360/...:Playerbot` tags, then syncs `storage/` unless `--skip-storage` is provided.) (Exports rebuilt images to `local-storage/images/acore-modules-images.tar`, bundling the `uprightbass360/...:modules-latest` and `uprightbass360/...:Playerbot` tags, then syncs `storage/` unless `--skip-storage` is provided.)
3. **Deploy on Remote Host** 3. **Deploy on Remote Host**
```bash ```bash
ssh docker-server ' ssh docker-server '
@@ -378,9 +380,9 @@ http://YOUR_SERVER_IP:4201
./deploy.sh --profile modules # Custom modules build ./deploy.sh --profile modules # Custom modules build
# Module staging and compilation # Module staging and compilation
./scripts/stage-modules.sh # Download and stage enabled modules ./scripts/stage-modules.sh # Download and stage enabled modules (preps upright playerbot builds)
./scripts/rebuild-with-modules.sh --yes # Force source rebuild with modules ./scripts/rebuild-with-modules.sh --yes # Rebuild uprightbass360/playerbot images with your modules
./scripts/setup-source.sh # Initialize/update source repositories ./scripts/setup-source.sh # Initialize/update source repositories (auto-switches to playerbot fork for modules)
# Module configuration management # Module configuration management
./scripts/copy-module-configs.sh # Create module .conf files ./scripts/copy-module-configs.sh # Create module .conf files

259
deploy.sh
View File

@@ -18,6 +18,16 @@ SKIP_REBUILD=0
WORLD_LOG_SINCE="" WORLD_LOG_SINCE=""
ASSUME_YES=0 ASSUME_YES=0
COMPILE_MODULE_VARS=(
MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE
MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS
MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD
MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER
MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK
MODULE_CHALLENGE_MODES MODULE_OLLAMA_CHAT MODULE_PLAYER_BOT_LEVEL_BRACKETS MODULE_STATBOOSTER MODULE_DUNGEON_RESPAWN
MODULE_SKELETON_MODULE MODULE_BG_SLAVERYVALLEY MODULE_AZEROTHSHARD MODULE_WORGOBLIN
)
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m' BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
info(){ printf '%b\n' "${BLUE} $*${NC}"; } info(){ printf '%b\n' "${BLUE} $*${NC}"; }
ok(){ printf '%b\n' "${GREEN}$*${NC}"; } ok(){ printf '%b\n' "${GREEN}$*${NC}"; }
@@ -50,11 +60,18 @@ Options:
--no-watch Do not tail worldserver logs after staging --no-watch Do not tail worldserver logs after staging
--keep-running Do not pre-stop runtime stack before rebuild --keep-running Do not pre-stop runtime stack before rebuild
--skip-rebuild Skip source rebuild even if modules require it --skip-rebuild Skip source rebuild even if modules require it
--yes, -y Auto-confirm the deployment prompt --yes, -y Auto-confirm deployment and rebuild prompts
-h, --help Show this help -h, --help Show this help
This command automates the module workflow (sync modules, rebuild source if needed, This command automates the module workflow: sync modules, rebuild source if needed,
stage the correct compose profile, and optionally watch worldserver logs). stage the correct compose profile, and optionally watch worldserver logs.
Rebuild Detection:
The script automatically detects when a module rebuild is required by checking:
• Module changes (sentinel file .requires_rebuild)
• C++ modules enabled but modules-latest Docker images missing
Set AUTO_REBUILD_ON_DEPLOY=1 in .env to skip rebuild prompts and auto-rebuild.
EOF EOF
} }
@@ -109,14 +126,16 @@ compose(){
} }
ensure_source_repo(){ ensure_source_repo(){
local module_playerbots local use_playerbot_source=0
module_playerbots="$(read_env MODULE_PLAYERBOTS "0")" if requires_playerbot_source; then
use_playerbot_source=1
fi
local local_root local local_root
local_root="$(read_env STORAGE_PATH_LOCAL "./local-storage")" local_root="$(read_env STORAGE_PATH_LOCAL "./local-storage")"
local_root="${local_root%/}" local_root="${local_root%/}"
[ -z "$local_root" ] && local_root="." [ -z "$local_root" ] && local_root="."
local default_source="${local_root}/source/azerothcore" local default_source="${local_root}/source/azerothcore"
if [ "$module_playerbots" = "1" ]; then if [ "$use_playerbot_source" = "1" ]; then
default_source="${local_root}/source/azerothcore-playerbots" default_source="${local_root}/source/azerothcore-playerbots"
fi fi
@@ -163,6 +182,114 @@ modules_need_rebuild(){
[[ -f "$sentinel" ]] [[ -f "$sentinel" ]]
} }
check_auto_rebuild_setting(){
local auto_rebuild
auto_rebuild="$(read_env AUTO_REBUILD_ON_DEPLOY "0")"
[[ "$auto_rebuild" = "1" ]]
}
detect_rebuild_reasons(){
local reasons=()
# Check sentinel file
if modules_need_rebuild; then
reasons+=("Module changes detected (sentinel file present)")
fi
# Check if any C++ modules are enabled but modules-latest images don't exist
local any_cxx_modules=0
local var
for var in "${COMPILE_MODULE_VARS[@]}"; do
if [ "$(read_env "$var" "0")" = "1" ]; then
any_cxx_modules=1
break
fi
done
if [ "$any_cxx_modules" = "1" ]; then
local authserver_modules_image
local worldserver_modules_image
authserver_modules_image="$(read_env AC_AUTHSERVER_IMAGE_MODULES "uprightbass360/azerothcore-wotlk-playerbots:authserver-modules-latest")"
worldserver_modules_image="$(read_env AC_WORLDSERVER_IMAGE_MODULES "uprightbass360/azerothcore-wotlk-playerbots:worldserver-modules-latest")"
if ! docker image inspect "$authserver_modules_image" >/dev/null 2>&1; then
reasons+=("C++ modules enabled but authserver modules image $authserver_modules_image is missing")
fi
if ! docker image inspect "$worldserver_modules_image" >/dev/null 2>&1; then
reasons+=("C++ modules enabled but worldserver modules image $worldserver_modules_image is missing")
fi
fi
printf '%s\n' "${reasons[@]}"
}
requires_playerbot_source(){
if [ "$(read_env MODULE_PLAYERBOTS "0")" = "1" ]; then
return 0
fi
local var
for var in "${COMPILE_MODULE_VARS[@]}"; do
if [ "$(read_env "$var" "0")" = "1" ]; then
return 0
fi
done
return 1
}
confirm_rebuild(){
local reasons=("$@")
if [ ${#reasons[@]} -eq 0 ]; then
return 1 # No rebuild needed
fi
echo
warn "Module rebuild appears to be required:"
local reason
for reason in "${reasons[@]}"; do
warn "$reason"
done
echo
# Check auto-rebuild setting
if check_auto_rebuild_setting; then
info "AUTO_REBUILD_ON_DEPLOY is enabled; proceeding with automatic rebuild."
return 0
fi
# Skip prompt if --yes flag is provided
if [ "$ASSUME_YES" -eq 1 ]; then
info "Auto-confirming rebuild (--yes supplied)."
return 0
fi
# Interactive prompt
info "This will rebuild AzerothCore from source with your enabled modules."
warn "⏱️ This process typically takes 15-45 minutes depending on your system."
echo
if [ -t 0 ]; then
local reply
read -r -p "Proceed with module rebuild? [y/N]: " reply
reply="${reply:-n}"
case "$reply" in
[Yy]*)
info "Rebuild confirmed."
return 0
;;
*)
warn "Rebuild declined. You can:"
warn " • Run with --skip-rebuild to deploy without rebuilding"
warn " • Set AUTO_REBUILD_ON_DEPLOY=1 in .env for automatic rebuilds"
warn " • Run './scripts/rebuild-with-modules.sh' manually later"
return 1
;;
esac
else
warn "Standard input is not interactive; use --yes to auto-confirm or --skip-rebuild to skip."
return 1
fi
}
determine_profile(){ determine_profile(){
if [ -n "$TARGET_PROFILE" ]; then if [ -n "$TARGET_PROFILE" ]; then
echo "$TARGET_PROFILE" echo "$TARGET_PROFILE"
@@ -178,49 +305,8 @@ determine_profile(){
return return
fi fi
local compile_vars=(
MODULE_AOE_LOOT
MODULE_LEARN_SPELLS
MODULE_FIREWORKS
MODULE_INDIVIDUAL_PROGRESSION
MODULE_AHBOT
MODULE_AUTOBALANCE
MODULE_TRANSMOG
MODULE_NPC_BUFFER
MODULE_DYNAMIC_XP
MODULE_SOLO_LFG
MODULE_1V1_ARENA
MODULE_PHASED_DUELS
MODULE_BREAKING_NEWS
MODULE_BOSS_ANNOUNCER
MODULE_ACCOUNT_ACHIEVEMENTS
MODULE_AUTO_REVIVE
MODULE_GAIN_HONOR_GUARD
MODULE_TIME_IS_TIME
MODULE_POCKET_PORTAL
MODULE_RANDOM_ENCHANTS
MODULE_SOLOCRAFT
MODULE_PVP_TITLES
MODULE_NPC_BEASTMASTER
MODULE_NPC_ENCHANTER
MODULE_INSTANCE_RESET
MODULE_LEVEL_GRANT
MODULE_ARAC
MODULE_ASSISTANT
MODULE_REAGENT_BANK
MODULE_CHALLENGE_MODES
MODULE_OLLAMA_CHAT
MODULE_PLAYER_BOT_LEVEL_BRACKETS
MODULE_STATBOOSTER
MODULE_DUNGEON_RESPAWN
MODULE_SKELETON_MODULE
MODULE_BG_SLAVERYVALLEY
MODULE_AZEROTHSHARD
MODULE_WORGOBLIN
)
local var local var
for var in "${compile_vars[@]}"; do for var in "${COMPILE_MODULE_VARS[@]}"; do
if [ "$(read_env "$var" "0")" = "1" ]; then if [ "$(read_env "$var" "0")" = "1" ]; then
echo "modules" echo "modules"
return return
@@ -253,53 +339,29 @@ rebuild_source(){
} }
tag_module_images(){ tag_module_images(){
local source_world="acore/ac-wotlk-worldserver:master" local source_auth
local source_auth="acore/ac-wotlk-authserver:master" local source_world
local target_auth
local target_world
local targets_world=() source_auth="$(read_env AC_AUTHSERVER_IMAGE_PLAYERBOTS "uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot")"
local targets_auth=() source_world="$(read_env AC_WORLDSERVER_IMAGE_PLAYERBOTS "uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot")"
target_auth="$(read_env AC_AUTHSERVER_IMAGE_MODULES "uprightbass360/azerothcore-wotlk-playerbots:authserver-modules-latest")"
target_world="$(read_env AC_WORLDSERVER_IMAGE_MODULES "uprightbass360/azerothcore-wotlk-playerbots:worldserver-modules-latest")"
targets_world+=("$(read_env AC_WORLDSERVER_IMAGE_MODULES "acore/ac-wotlk-worldserver:modules-latest")") if docker image inspect "$source_auth" >/dev/null 2>&1; then
targets_world+=("$(read_env AC_WORLDSERVER_IMAGE_PLAYERBOTS "uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot")") docker tag "$source_auth" "$target_auth"
targets_auth+=("$(read_env AC_AUTHSERVER_IMAGE_MODULES "acore/ac-wotlk-authserver:modules-latest")") ok "Tagged $target_auth from $source_auth"
targets_auth+=("$(read_env AC_AUTHSERVER_IMAGE_PLAYERBOTS "uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot")")
local tagged_world=()
local tagged_auth=()
tag_image(){
local src="$1" target="$2" label="$3"
[[ -n "$target" ]] || return 0
case "$label" in
world) for image in "${tagged_world[@]}"; do [[ "$image" == "$target" ]] && return 0; done ;;
auth) for image in "${tagged_auth[@]}"; do [[ "$image" == "$target" ]] && return 0; done ;;
esac
case "$target" in
*modules-latest*)
if docker image inspect "$src" >/dev/null 2>&1; then
docker tag "$src" "$target"
ok "Tagged $target from $src ($label)"
else else
warn "Source image $src not found; skipping tag for $label" warn "Source authserver image $source_auth not found; skipping modules tag"
fi fi
;;
*)
info "Skipping tag for $label image $target (non modules-latest)"
return 0
;;
esac
case "$label" in
world) tagged_world+=("$target") ;;
auth) tagged_auth+=("$target") ;;
esac
}
for target in "${targets_world[@]}"; do if docker image inspect "$source_world" >/dev/null 2>&1; then
tag_image "$source_world" "$target" world docker tag "$source_world" "$target_world"
done ok "Tagged $target_world from $source_world"
for target in "${targets_auth[@]}"; do else
tag_image "$source_auth" "$target" auth warn "Source worldserver image $source_world not found; skipping modules tag"
done fi
} }
stage_runtime(){ stage_runtime(){
@@ -396,13 +458,26 @@ main(){
sync_modules sync_modules
local did_rebuild=0 local did_rebuild=0
if modules_need_rebuild; then local rebuild_reasons
readarray -t rebuild_reasons < <(detect_rebuild_reasons)
if [ ${#rebuild_reasons[@]} -gt 0 ]; then
if [ "$SKIP_REBUILD" -eq 1 ]; then if [ "$SKIP_REBUILD" -eq 1 ]; then
warn "Modules require rebuild, but --skip-rebuild was provided." warn "Modules require rebuild, but --skip-rebuild was provided:"
local reason
for reason in "${rebuild_reasons[@]}"; do
warn "$reason"
done
warn "Proceeding without rebuild; deployment may fail if modules-latest images are missing."
else else
if confirm_rebuild "${rebuild_reasons[@]}"; then
show_step 4 5 "Building realm with modules (this may take 15-45 minutes)" show_step 4 5 "Building realm with modules (this may take 15-45 minutes)"
rebuild_source "$src_dir" rebuild_source "$src_dir"
did_rebuild=1 did_rebuild=1
else
err "Rebuild required but declined. Use --skip-rebuild to force deployment without rebuild."
exit 1
fi
fi fi
else else
info "No module rebuild required." info "No module rebuild required."

View File

@@ -45,15 +45,15 @@ read_env(){
} }
default_source_path(){ default_source_path(){
local module_playerbots local require_playerbot
module_playerbots="$(read_env MODULE_PLAYERBOTS "0")" require_playerbot="$(modules_require_playerbot_source)"
local local_root local local_root
local_root="$(read_env STORAGE_PATH_LOCAL "./local-storage")" local_root="$(read_env STORAGE_PATH_LOCAL "./local-storage")"
local_root="${local_root%/}" local_root="${local_root%/}"
if [[ -z "$local_root" ]]; then if [[ -z "$local_root" ]]; then
local_root="." local_root="."
fi fi
if [ "$module_playerbots" = "1" ]; then if [ "$require_playerbot" = "1" ]; then
echo "${local_root}/source/azerothcore-playerbots" echo "${local_root}/source/azerothcore-playerbots"
else else
echo "${local_root}/source/azerothcore" echo "${local_root}/source/azerothcore"
@@ -84,6 +84,31 @@ ASSUME_YES=0
SOURCE_OVERRIDE="" SOURCE_OVERRIDE=""
SKIP_STOP=0 SKIP_STOP=0
COMPILE_MODULE_KEYS=(
MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE
MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS
MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD
MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER
MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK
MODULE_CHALLENGE_MODES MODULE_OLLAMA_CHAT MODULE_PLAYER_BOT_LEVEL_BRACKETS MODULE_STATBOOSTER MODULE_DUNGEON_RESPAWN
MODULE_SKELETON_MODULE MODULE_BG_SLAVERYVALLEY MODULE_AZEROTHSHARD MODULE_WORGOBLIN
)
modules_require_playerbot_source(){
if [ "$(read_env MODULE_PLAYERBOTS "0")" = "1" ]; then
echo 1
return
fi
local key
for key in "${COMPILE_MODULE_KEYS[@]}"; do
if [ "$(read_env "$key" "0")" = "1" ]; then
echo 1
return
fi
done
echo 0
}
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--yes|-y) ASSUME_YES=1; shift;; --yes|-y) ASSUME_YES=1; shift;;
@@ -246,13 +271,41 @@ echo "🚀 Building AzerothCore with modules..."
docker compose build --no-cache docker compose build --no-cache
echo "🔖 Tagging modules-latest images" echo "🔖 Tagging modules-latest images"
docker tag acore/ac-wotlk-worldserver:master acore/ac-wotlk-worldserver:modules-latest
docker tag acore/ac-wotlk-authserver:master acore/ac-wotlk-authserver:modules-latest
if [ "$(read_env MODULE_PLAYERBOTS "0")" = "1" ]; then # Get image names and tags from .env.template
echo "🔁 Tagging playerbot images uprightbass360/azerothcore-wotlk-playerbots:*" TEMPLATE_FILE="$PROJECT_DIR/.env.template"
docker tag acore/ac-wotlk-worldserver:modules-latest uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot get_template_value() {
docker tag acore/ac-wotlk-authserver:modules-latest uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot local key="$1"
local fallback="$2"
if [ -f "$TEMPLATE_FILE" ]; then
local value
value=$(grep "^${key}=" "$TEMPLATE_FILE" | head -1 | cut -d'=' -f2- | sed 's/^"\(.*\)"$/\1/')
if [[ "$value" =~ ^\$\{[^}]*:-([^}]*)\}$ ]]; then
value="${BASH_REMATCH[1]}"
fi
[ -n "$value" ] && echo "$value" || echo "$fallback"
else
echo "$fallback"
fi
}
TARGET_AUTHSERVER_IMAGE="$(read_env AC_AUTHSERVER_IMAGE_MODULES "$(get_template_value "AC_AUTHSERVER_IMAGE_MODULES")")"
TARGET_WORLDSERVER_IMAGE="$(read_env AC_WORLDSERVER_IMAGE_MODULES "$(get_template_value "AC_WORLDSERVER_IMAGE_MODULES")")"
PLAYERBOTS_AUTHSERVER_IMAGE="$(read_env AC_AUTHSERVER_IMAGE_PLAYERBOTS "$(get_template_value "AC_AUTHSERVER_IMAGE_PLAYERBOTS")")"
PLAYERBOTS_WORLDSERVER_IMAGE="$(read_env AC_WORLDSERVER_IMAGE_PLAYERBOTS "$(get_template_value "AC_WORLDSERVER_IMAGE_PLAYERBOTS")")"
echo "🔁 Tagging modules images from playerbot build artifacts"
if docker image inspect "$PLAYERBOTS_AUTHSERVER_IMAGE" >/dev/null 2>&1; then
docker tag "$PLAYERBOTS_AUTHSERVER_IMAGE" "$TARGET_AUTHSERVER_IMAGE"
else
echo "⚠️ Warning: $PLAYERBOTS_AUTHSERVER_IMAGE not found, skipping authserver tag"
fi
if docker image inspect "$PLAYERBOTS_WORLDSERVER_IMAGE" >/dev/null 2>&1; then
docker tag "$PLAYERBOTS_WORLDSERVER_IMAGE" "$TARGET_WORLDSERVER_IMAGE"
else
echo "⚠️ Warning: $PLAYERBOTS_WORLDSERVER_IMAGE not found, skipping worldserver tag"
fi fi
show_rebuild_step 5 5 "Cleaning up build containers" show_rebuild_step 5 5 "Cleaning up build containers"

View File

@@ -14,12 +14,32 @@ PROJECT_ROOT="$(pwd)"
# Default values # Default values
MODULE_PLAYERBOTS="${MODULE_PLAYERBOTS:-0}" MODULE_PLAYERBOTS="${MODULE_PLAYERBOTS:-0}"
NEEDS_CXX_REBUILD="${NEEDS_CXX_REBUILD:-0}"
COMPILE_MODULE_KEYS=(
MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE
MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS
MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD
MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER
MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK
MODULE_CHALLENGE_MODES MODULE_OLLAMA_CHAT MODULE_PLAYER_BOT_LEVEL_BRACKETS MODULE_STATBOOSTER MODULE_DUNGEON_RESPAWN
MODULE_SKELETON_MODULE MODULE_BG_SLAVERYVALLEY MODULE_AZEROTHSHARD MODULE_WORGOBLIN
)
if [ "$NEEDS_CXX_REBUILD" != "1" ]; then
for key in "${COMPILE_MODULE_KEYS[@]}"; do
if [ "${!key:-0}" = "1" ]; then
NEEDS_CXX_REBUILD=1
break
fi
done
fi
LOCAL_STORAGE_ROOT="${STORAGE_PATH_LOCAL:-./local-storage}" LOCAL_STORAGE_ROOT="${STORAGE_PATH_LOCAL:-./local-storage}"
DEFAULT_STANDARD_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore" DEFAULT_STANDARD_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore"
DEFAULT_PLAYERBOTS_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore-playerbots" DEFAULT_PLAYERBOTS_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore-playerbots"
SOURCE_PATH_DEFAULT="$DEFAULT_STANDARD_PATH" SOURCE_PATH_DEFAULT="$DEFAULT_STANDARD_PATH"
if [ "$MODULE_PLAYERBOTS" = "1" ]; then if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then
SOURCE_PATH_DEFAULT="$DEFAULT_PLAYERBOTS_PATH" SOURCE_PATH_DEFAULT="$DEFAULT_PLAYERBOTS_PATH"
fi fi
SOURCE_PATH="${MODULES_REBUILD_SOURCE_PATH:-$SOURCE_PATH_DEFAULT}" SOURCE_PATH="${MODULES_REBUILD_SOURCE_PATH:-$SOURCE_PATH_DEFAULT}"
@@ -53,7 +73,7 @@ ACORE_REPO_PLAYERBOTS="${ACORE_REPO_PLAYERBOTS:-https://github.com/uprightbass36
ACORE_BRANCH_PLAYERBOTS="${ACORE_BRANCH_PLAYERBOTS:-Playerbot}" ACORE_BRANCH_PLAYERBOTS="${ACORE_BRANCH_PLAYERBOTS:-Playerbot}"
# Repository and branch selection based on playerbots mode # Repository and branch selection based on playerbots mode
if [ "$MODULE_PLAYERBOTS" = "1" ]; then if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then
REPO_URL="$ACORE_REPO_PLAYERBOTS" REPO_URL="$ACORE_REPO_PLAYERBOTS"
BRANCH="$ACORE_BRANCH_PLAYERBOTS" BRANCH="$ACORE_BRANCH_PLAYERBOTS"
echo "📌 Playerbots mode: Using $REPO_URL, branch $BRANCH" echo "📌 Playerbots mode: Using $REPO_URL, branch $BRANCH"

View File

@@ -182,10 +182,11 @@ echo "🎯 Target profile: services-$TARGET_PROFILE"
# Check if source rebuild is needed for modules profile # Check if source rebuild is needed for modules profile
REBUILD_NEEDED=0 REBUILD_NEEDED=0
TARGET_WORLDSERVER_IMAGE_MODULES="$(read_env AC_WORLDSERVER_IMAGE_MODULES "uprightbass360/azerothcore-wotlk-playerbots:worldserver-modules-latest")"
if [ "$TARGET_PROFILE" = "modules" ]; then if [ "$TARGET_PROFILE" = "modules" ]; then
# Check if source image exists # Check if source image exists
if ! docker image inspect "acore/ac-wotlk-worldserver:modules-latest" >/dev/null 2>&1; then if ! docker image inspect "$TARGET_WORLDSERVER_IMAGE_MODULES" >/dev/null 2>&1; then
echo "📦 Custom worldserver image not found - rebuild needed" echo "📦 Modules image $TARGET_WORLDSERVER_IMAGE_MODULES not found - rebuild needed"
REBUILD_NEEDED=1 REBUILD_NEEDED=1
elif [ -f "$SENTINEL_FILE" ]; then elif [ -f "$SENTINEL_FILE" ]; then
echo "🔄 Modules changed since last build - rebuild needed" echo "🔄 Modules changed since last build - rebuild needed"

497
setup.sh
View File

@@ -6,6 +6,147 @@ set -e
# ============================================== # ==============================================
# Mirrors options from scripts/setup-server.sh but targets ac-compose/.env # Mirrors options from scripts/setup-server.sh but targets ac-compose/.env
# Get script directory for template reading
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ==============================================
# Constants (auto-loaded from .env.template)
# ==============================================
# Function to read value from .env.template (required)
get_template_value() {
local key="$1"
local template_file="$SCRIPT_DIR/.env.template"
if [ ! -f "$template_file" ]; then
echo "ERROR: .env.template file not found at $template_file" >&2
echo "This file is required for setup.sh to function properly." >&2
exit 1
fi
# Extract value, handling variable expansion syntax like ${VAR:-default}
local value
value=$(grep "^${key}=" "$template_file" | head -1 | cut -d'=' -f2- | sed 's/^"\(.*\)"$/\1/')
# Handle ${VAR:-default} syntax by extracting the default value
if [[ "$value" =~ ^\$\{[^}]*:-([^}]*)\}$ ]]; then
value="${BASH_REMATCH[1]}"
fi
if [ -z "$value" ]; then
echo "ERROR: Required key '$key' not found in .env.template" >&2
exit 1
fi
echo "$value"
}
# Load constants from .env.template (required)
readonly DEFAULT_MYSQL_PASSWORD="$(get_template_value "MYSQL_ROOT_PASSWORD")"
readonly DEFAULT_REALM_PORT="$(get_template_value "WORLD_EXTERNAL_PORT")"
readonly DEFAULT_AUTH_PORT="$(get_template_value "AUTH_EXTERNAL_PORT")"
readonly DEFAULT_SOAP_PORT="$(get_template_value "SOAP_EXTERNAL_PORT")"
readonly DEFAULT_MYSQL_PORT="$(get_template_value "MYSQL_EXTERNAL_PORT")"
readonly DEFAULT_PLAYERBOT_MAX="$(get_template_value "PLAYERBOT_MAX_BOTS")"
readonly DEFAULT_LOCAL_STORAGE="$(get_template_value "STORAGE_PATH")"
# Permission schemes (hardcoded as not in template)
readonly PERMISSION_LOCAL_USER="0:0"
readonly PERMISSION_NFS_USER="1001:1000"
readonly DEFAULT_CUSTOM_UID="1000"
readonly DEFAULT_CUSTOM_GID="1000"
# Static values
readonly DEFAULT_LOCAL_ADDRESS="127.0.0.1"
readonly DEFAULT_FALLBACK_LAN_IP="192.168.1.100"
readonly DEFAULT_DOMAIN_PLACEHOLDER="your-domain.com"
readonly DEFAULT_BACKUP_DAYS="3"
readonly DEFAULT_BACKUP_HOURS="6"
readonly DEFAULT_BACKUP_TIME="09"
readonly DEFAULT_NFS_STORAGE="/nfs/azerothcore"
readonly DEFAULT_MOUNT_STORAGE="/mnt/azerothcore-data"
# Docker images (from .env.template)
readonly DEFAULT_MYSQL_IMAGE="$(get_template_value "MYSQL_IMAGE")"
readonly DEFAULT_AC_DB_IMPORT_IMAGE="$(get_template_value "AC_DB_IMPORT_IMAGE")"
readonly DEFAULT_AC_AUTHSERVER_IMAGE="$(get_template_value "AC_AUTHSERVER_IMAGE")"
readonly DEFAULT_AC_WORLDSERVER_IMAGE="$(get_template_value "AC_WORLDSERVER_IMAGE")"
readonly DEFAULT_AC_CLIENT_DATA_IMAGE="$(get_template_value "AC_CLIENT_DATA_IMAGE")"
readonly DEFAULT_AUTH_IMAGE_PLAYERBOTS="$(get_template_value "AC_AUTHSERVER_IMAGE_PLAYERBOTS")"
readonly DEFAULT_WORLD_IMAGE_PLAYERBOTS="$(get_template_value "AC_WORLDSERVER_IMAGE_PLAYERBOTS")"
readonly DEFAULT_CLIENT_DATA_IMAGE_PLAYERBOTS="$(get_template_value "AC_CLIENT_DATA_IMAGE_PLAYERBOTS")"
readonly DEFAULT_AUTH_IMAGE_MODULES="$(get_template_value "AC_AUTHSERVER_IMAGE_MODULES")"
readonly DEFAULT_WORLD_IMAGE_MODULES="$(get_template_value "AC_WORLDSERVER_IMAGE_MODULES")"
# Database names
readonly DEFAULT_DB_AUTH_NAME="$(get_template_value "DB_AUTH_NAME")"
readonly DEFAULT_DB_WORLD_NAME="$(get_template_value "DB_WORLD_NAME")"
readonly DEFAULT_DB_CHARACTERS_NAME="$(get_template_value "DB_CHARACTERS_NAME")"
readonly DEFAULT_DB_PLAYERBOTS_NAME="$(get_template_value "DB_PLAYERBOTS_NAME")"
# Container names
readonly DEFAULT_CONTAINER_MYSQL="$(get_template_value "CONTAINER_MYSQL")"
readonly DEFAULT_COMPOSE_PROJECT_NAME="$(get_template_value "COMPOSE_PROJECT_NAME")"
readonly DEFAULT_CLIENT_DATA_VOLUME="$(get_template_value "CLIENT_DATA_VOLUME")"
# Version constants
readonly DEFAULT_CLIENT_DATA_VERSION="$(get_template_value "CLIENT_DATA_VERSION")"
# Network configuration
readonly DEFAULT_NETWORK_NAME="$(get_template_value "NETWORK_NAME")"
readonly DEFAULT_NETWORK_SUBNET="$(get_template_value "NETWORK_SUBNET")"
readonly DEFAULT_NETWORK_GATEWAY="$(get_template_value "NETWORK_GATEWAY")"
# MySQL configuration
readonly DEFAULT_MYSQL_CHARACTER_SET="$(get_template_value "MYSQL_CHARACTER_SET")"
readonly DEFAULT_MYSQL_COLLATION="$(get_template_value "MYSQL_COLLATION")"
readonly DEFAULT_MYSQL_MAX_CONNECTIONS="$(get_template_value "MYSQL_MAX_CONNECTIONS")"
readonly DEFAULT_MYSQL_INNODB_BUFFER_POOL_SIZE="$(get_template_value "MYSQL_INNODB_BUFFER_POOL_SIZE")"
readonly DEFAULT_MYSQL_INNODB_LOG_FILE_SIZE="$(get_template_value "MYSQL_INNODB_LOG_FILE_SIZE")"
readonly DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY="$(get_template_value "MYSQL_INNODB_REDO_LOG_CAPACITY")"
readonly DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE="$(get_template_value "MYSQL_RUNTIME_TMPFS_SIZE")"
# Paths
readonly DEFAULT_HOST_ZONEINFO_PATH="$(get_template_value "HOST_ZONEINFO_PATH")"
readonly DEFAULT_ELUNA_SCRIPT_PATH="$(get_template_value "AC_ELUNA_SCRIPT_PATH")"
# Tool configuration
readonly DEFAULT_PMA_EXTERNAL_PORT="$(get_template_value "PMA_EXTERNAL_PORT")"
readonly DEFAULT_PMA_UPLOAD_LIMIT="$(get_template_value "PMA_UPLOAD_LIMIT")"
readonly DEFAULT_PMA_MEMORY_LIMIT="$(get_template_value "PMA_MEMORY_LIMIT")"
readonly DEFAULT_PMA_MAX_EXECUTION_TIME="$(get_template_value "PMA_MAX_EXECUTION_TIME")"
readonly DEFAULT_KEIRA3_EXTERNAL_PORT="$(get_template_value "KEIRA3_EXTERNAL_PORT")"
readonly DEFAULT_PMA_USER="$(get_template_value "PMA_USER")"
readonly DEFAULT_PMA_ARBITRARY="$(get_template_value "PMA_ARBITRARY")"
readonly DEFAULT_PMA_ABSOLUTE_URI="$(get_template_value "PMA_ABSOLUTE_URI")"
# Module preset names (not in template)
readonly DEFAULT_PRESET_SUGGESTED="suggested-modules"
readonly DEFAULT_PRESET_PLAYERBOTS="playerbots-suggested-modules"
# Internal ports
readonly DEFAULT_AUTH_INTERNAL_PORT="$(get_template_value "AUTH_PORT")"
readonly DEFAULT_WORLD_INTERNAL_PORT="$(get_template_value "WORLD_PORT")"
readonly DEFAULT_SOAP_INTERNAL_PORT="$(get_template_value "SOAP_PORT")"
readonly DEFAULT_MYSQL_INTERNAL_PORT="$(get_template_value "MYSQL_PORT")"
# System configuration
readonly DEFAULT_TZ="$(get_template_value "TZ")"
readonly DEFAULT_MYSQL_ROOT_HOST="$(get_template_value "MYSQL_ROOT_HOST")"
readonly DEFAULT_MYSQL_USER="$(get_template_value "MYSQL_USER")"
# Eluna configuration
readonly DEFAULT_ELUNA_ENABLED="$(get_template_value "AC_ELUNA_ENABLED")"
readonly DEFAULT_ELUNA_TRACE_BACK="$(get_template_value "AC_ELUNA_TRACE_BACK")"
readonly DEFAULT_ELUNA_AUTO_RELOAD="$(get_template_value "AC_ELUNA_AUTO_RELOAD")"
readonly DEFAULT_ELUNA_BYTECODE_CACHE="$(get_template_value "AC_ELUNA_BYTECODE_CACHE")"
readonly DEFAULT_ELUNA_AUTO_RELOAD_INTERVAL="$(get_template_value "AC_ELUNA_AUTO_RELOAD_INTERVAL")"
readonly DEFAULT_ELUNA_REQUIRE_PATHS="$(get_template_value "AC_ELUNA_REQUIRE_PATHS")"
readonly DEFAULT_ELUNA_REQUIRE_CPATHS="$(get_template_value "AC_ELUNA_REQUIRE_CPATHS")"
# Route detection IP (not in template)
readonly ROUTE_DETECTION_IP="1.1.1.1"
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; NC='\033[0m' RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; NC='\033[0m'
say(){ local t=$1; shift; case "$t" in say(){ local t=$1; shift; case "$t" in
INFO) echo -e "${BLUE} $*${NC}";; INFO) echo -e "${BLUE} $*${NC}";;
@@ -19,8 +160,6 @@ validate_ip(){ [[ $1 =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; }
validate_port(){ [[ $1 =~ ^[0-9]+$ ]] && [ $1 -ge 1 ] && [ $1 -le 65535 ]; } validate_port(){ [[ $1 =~ ^[0-9]+$ ]] && [ $1 -ge 1 ] && [ $1 -le 65535 ]; }
validate_number(){ [[ $1 =~ ^[0-9]+$ ]]; } validate_number(){ [[ $1 =~ ^[0-9]+$ ]]; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NON_INTERACTIVE=0 NON_INTERACTIVE=0
ask(){ ask(){
@@ -92,62 +231,6 @@ normalize_module_name(){
declare -A MODULE_ENABLE_SET=() declare -A MODULE_ENABLE_SET=()
declare -a COMPOSE_CMD=()
resolve_compose_command(){
if [ ${#COMPOSE_CMD[@]} -gt 0 ]; then
return 0
fi
if command -v docker >/dev/null 2>&1; then
if docker compose version >/dev/null 2>&1; then
COMPOSE_CMD=(docker compose)
return 0
fi
fi
if command -v docker-compose >/dev/null 2>&1; then
COMPOSE_CMD=(docker-compose)
return 0
fi
COMPOSE_CMD=()
return 1
}
modules_directory_has_content(){
local dir="$1"
[ -d "$dir" ] || return 1
local first_entry
first_entry="$(find "$dir" -mindepth 1 -maxdepth 1 -type d -print -quit 2>/dev/null)"
[ -n "$first_entry" ]
}
ensure_modules_staged(){
local storage_abs="$1" needs_cxx="$2" run_now="$3"
if [ "$needs_cxx" != "1" ] || [ "$run_now" != "1" ]; then
return 0
fi
local modules_dir="${storage_abs}/modules"
local config_dir="${storage_abs}/config"
mkdir -p "$modules_dir" "$config_dir"
if modules_directory_has_content "$modules_dir"; then
return 0
fi
if ! resolve_compose_command; then
say WARNING "Docker Compose not detected; skipping automatic module staging."
return 1
fi
say INFO "Staging module repositories via ${COMPOSE_CMD[*]} run --rm --no-deps ac-modules"
if ! "${COMPOSE_CMD[@]}" --profile modules run --rm --no-deps ac-modules; then
say WARNING "Module staging failed; repositories may be incomplete."
return 1
fi
return 0
}
KNOWN_MODULE_VARS=( KNOWN_MODULE_VARS=(
MODULE_PLAYERBOTS MODULE_PLAYERBOTS
MODULE_AOE_LOOT MODULE_AOE_LOOT
@@ -221,11 +304,11 @@ apply_module_preset(){
done done
} }
DEFAULT_PRESET_SUGGESTED="suggested-modules"
DEFAULT_PRESET_PLAYERBOTS="playerbots-suggested-modules"
show_wow_header() { show_wow_header() {
clear if [ -t 1 ] && command -v clear >/dev/null 2>&1; then
clear >/dev/null 2>&1 || true
fi
echo -e "${RED}" echo -e "${RED}"
cat <<'EOF' cat <<'EOF'
@@ -562,20 +645,20 @@ fi
if [ -n "$CLI_SERVER_ADDRESS" ]; then if [ -n "$CLI_SERVER_ADDRESS" ]; then
SERVER_ADDRESS="$CLI_SERVER_ADDRESS" SERVER_ADDRESS="$CLI_SERVER_ADDRESS"
elif [ "$DEPLOYMENT_TYPE" = "local" ]; then elif [ "$DEPLOYMENT_TYPE" = "local" ]; then
SERVER_ADDRESS=127.0.0.1 SERVER_ADDRESS=$DEFAULT_LOCAL_ADDRESS
elif [ "$DEPLOYMENT_TYPE" = "lan" ]; then elif [ "$DEPLOYMENT_TYPE" = "lan" ]; then
local LAN_IP local LAN_IP
LAN_IP=$(ip route get 1.1.1.1 2>/dev/null | awk 'NR==1{print $7}') LAN_IP=$(ip route get $ROUTE_DETECTION_IP 2>/dev/null | awk 'NR==1{print $7}')
SERVER_ADDRESS=$(ask "Enter server IP address" "${CLI_SERVER_ADDRESS:-${LAN_IP:-192.168.1.100}}" validate_ip) SERVER_ADDRESS=$(ask "Enter server IP address" "${CLI_SERVER_ADDRESS:-${LAN_IP:-$DEFAULT_FALLBACK_LAN_IP}}" validate_ip)
else else
SERVER_ADDRESS=$(ask "Enter server address (IP or domain)" "${CLI_SERVER_ADDRESS:-your-domain.com}" ) SERVER_ADDRESS=$(ask "Enter server address (IP or domain)" "${CLI_SERVER_ADDRESS:-$DEFAULT_DOMAIN_PLACEHOLDER}" )
fi fi
local REALM_PORT AUTH_EXTERNAL_PORT SOAP_EXTERNAL_PORT MYSQL_EXTERNAL_PORT local REALM_PORT AUTH_EXTERNAL_PORT SOAP_EXTERNAL_PORT MYSQL_EXTERNAL_PORT
REALM_PORT=$(ask "Enter client connection port" "${CLI_REALM_PORT:-8215}" validate_port) REALM_PORT=$(ask "Enter client connection port" "${CLI_REALM_PORT:-$DEFAULT_REALM_PORT}" validate_port)
AUTH_EXTERNAL_PORT=$(ask "Enter auth server port" "${CLI_AUTH_PORT:-3784}" validate_port) AUTH_EXTERNAL_PORT=$(ask "Enter auth server port" "${CLI_AUTH_PORT:-$DEFAULT_AUTH_PORT}" validate_port)
SOAP_EXTERNAL_PORT=$(ask "Enter SOAP API port" "${CLI_SOAP_PORT:-7778}" validate_port) SOAP_EXTERNAL_PORT=$(ask "Enter SOAP API port" "${CLI_SOAP_PORT:-$DEFAULT_SOAP_PORT}" validate_port)
MYSQL_EXTERNAL_PORT=$(ask "Enter MySQL external port" "${CLI_MYSQL_PORT:-64306}" validate_port) MYSQL_EXTERNAL_PORT=$(ask "Enter MySQL external port" "${CLI_MYSQL_PORT:-$DEFAULT_MYSQL_PORT}" validate_port)
# Permission scheme # Permission scheme
say HEADER "PERMISSION SCHEME" say HEADER "PERMISSION SCHEME"
@@ -594,17 +677,17 @@ fi
fi fi
case "${PERMISSION_SCHEME_INPUT,,}" in case "${PERMISSION_SCHEME_INPUT,,}" in
1|local) 1|local)
CONTAINER_USER="0:0" CONTAINER_USER="$PERMISSION_LOCAL_USER"
PERMISSION_SCHEME_NAME="local" PERMISSION_SCHEME_NAME="local"
;; ;;
2|nfs) 2|nfs)
CONTAINER_USER="1001:1000" CONTAINER_USER="$PERMISSION_NFS_USER"
PERMISSION_SCHEME_NAME="nfs" PERMISSION_SCHEME_NAME="nfs"
;; ;;
3|custom) 3|custom)
local uid gid local uid gid
uid="${CLI_CUSTOM_UID:-$(ask "Enter PUID (user id)" 1000 validate_number)}" uid="${CLI_CUSTOM_UID:-$(ask "Enter PUID (user id)" $DEFAULT_CUSTOM_UID validate_number)}"
gid="${CLI_CUSTOM_GID:-$(ask "Enter PGID (group id)" 1000 validate_number)}" gid="${CLI_CUSTOM_GID:-$(ask "Enter PGID (group id)" $DEFAULT_CUSTOM_GID validate_number)}"
CONTAINER_USER="${uid}:${gid}" CONTAINER_USER="${uid}:${gid}"
PERMISSION_SCHEME_NAME="custom" PERMISSION_SCHEME_NAME="custom"
;; ;;
@@ -625,7 +708,7 @@ fi
fi fi
# DB config # DB config
say HEADER "DATABASE CONFIGURATION" say HEADER "DATABASE CONFIGURATION"
local MYSQL_ROOT_PASSWORD; MYSQL_ROOT_PASSWORD=$(ask "Enter MySQL root password" "${CLI_MYSQL_PASSWORD:-azerothcore123}") local MYSQL_ROOT_PASSWORD; MYSQL_ROOT_PASSWORD=$(ask "Enter MySQL root password" "${CLI_MYSQL_PASSWORD:-$DEFAULT_MYSQL_PASSWORD}")
# Storage # Storage
say HEADER "STORAGE CONFIGURATION" say HEADER "STORAGE CONFIGURATION"
@@ -633,10 +716,10 @@ fi
if [ -n "$CLI_STORAGE_PATH" ]; then if [ -n "$CLI_STORAGE_PATH" ]; then
STORAGE_PATH="$CLI_STORAGE_PATH" STORAGE_PATH="$CLI_STORAGE_PATH"
elif [ "$DEPLOYMENT_TYPE" = "local" ]; then elif [ "$DEPLOYMENT_TYPE" = "local" ]; then
STORAGE_PATH=./storage STORAGE_PATH=$DEFAULT_LOCAL_STORAGE
else else
if [ "$NON_INTERACTIVE" = "1" ]; then if [ "$NON_INTERACTIVE" = "1" ]; then
STORAGE_PATH=/mnt/azerothcore-data STORAGE_PATH=$DEFAULT_MOUNT_STORAGE
else else
echo "1) 💾 ./storage (local)" echo "1) 💾 ./storage (local)"
echo "2) 🌐 /nfs/azerothcore (NFS)" echo "2) 🌐 /nfs/azerothcore (NFS)"
@@ -644,9 +727,9 @@ fi
while true; do while true; do
read -p "$(echo -e "${YELLOW}🔧 Select storage option [1-3]: ${NC}")" s read -p "$(echo -e "${YELLOW}🔧 Select storage option [1-3]: ${NC}")" s
case "$s" in case "$s" in
1) STORAGE_PATH=./storage; break;; 1) STORAGE_PATH=$DEFAULT_LOCAL_STORAGE; break;;
2) STORAGE_PATH=/nfs/azerothcore; break;; 2) STORAGE_PATH=$DEFAULT_NFS_STORAGE; break;;
3) STORAGE_PATH=$(ask "Enter custom storage path" "/mnt/azerothcore-data"); break;; 3) STORAGE_PATH=$(ask "Enter custom storage path" "$DEFAULT_MOUNT_STORAGE"); break;;
*) say ERROR "Please select 1, 2, or 3";; *) say ERROR "Please select 1, 2, or 3";;
esac esac
done done
@@ -656,11 +739,11 @@ fi
# Backup # Backup
say HEADER "BACKUP CONFIGURATION" say HEADER "BACKUP CONFIGURATION"
local BACKUP_RETENTION_DAYS BACKUP_RETENTION_HOURS BACKUP_DAILY_TIME local BACKUP_RETENTION_DAYS BACKUP_RETENTION_HOURS BACKUP_DAILY_TIME
BACKUP_RETENTION_DAYS=$(ask "Daily backups retention (days)" "${CLI_BACKUP_DAYS:-3}" validate_number) BACKUP_RETENTION_DAYS=$(ask "Daily backups retention (days)" "${CLI_BACKUP_DAYS:-$DEFAULT_BACKUP_DAYS}" validate_number)
BACKUP_RETENTION_HOURS=$(ask "Hourly backups retention (hours)" "${CLI_BACKUP_HOURS:-6}" validate_number) BACKUP_RETENTION_HOURS=$(ask "Hourly backups retention (hours)" "${CLI_BACKUP_HOURS:-$DEFAULT_BACKUP_HOURS}" validate_number)
BACKUP_DAILY_TIME=$(ask "Daily backup hour (00-23, UTC)" "${CLI_BACKUP_TIME:-09}" validate_number) BACKUP_DAILY_TIME=$(ask "Daily backup hour (00-23, UTC)" "${CLI_BACKUP_TIME:-$DEFAULT_BACKUP_TIME}" validate_number)
local MODE="" local MODE_SELECTION=""
local MODE_PRESET_NAME="" local MODE_PRESET_NAME=""
declare -A MODULE_PRESET_CONFIGS=() declare -A MODULE_PRESET_CONFIGS=()
declare -a MODULE_PRESET_ORDER=() declare -a MODULE_PRESET_ORDER=()
@@ -690,7 +773,7 @@ fi
if [ -n "$CLI_MODULE_PRESET" ]; then if [ -n "$CLI_MODULE_PRESET" ]; then
if [ -n "${MODULE_PRESET_CONFIGS[$CLI_MODULE_PRESET]:-}" ]; then if [ -n "${MODULE_PRESET_CONFIGS[$CLI_MODULE_PRESET]:-}" ]; then
MODE="preset" MODE_SELECTION="preset"
MODE_PRESET_NAME="$CLI_MODULE_PRESET" MODE_PRESET_NAME="$CLI_MODULE_PRESET"
else else
say ERROR "Unknown module preset: $CLI_MODULE_PRESET" say ERROR "Unknown module preset: $CLI_MODULE_PRESET"
@@ -698,39 +781,38 @@ fi
fi fi
fi fi
if [ -n "$MODE" ] && [ "$MODE" != "preset" ]; then if [ -n "$MODE_SELECTION" ] && [ "$MODE_SELECTION" != "preset" ]; then
MODE_PRESET_NAME="" MODE_PRESET_NAME=""
fi fi
if [ -n "$CLI_MODULE_MODE" ]; then if [ -n "$CLI_MODULE_MODE" ]; then
case "${CLI_MODULE_MODE,,}" in case "${CLI_MODULE_MODE,,}" in
1|suggested) MODE=1 ;; 1|suggested) MODE_SELECTION=1 ;;
2|playerbots) MODE=2 ;; 2|playerbots) MODE_SELECTION=2 ;;
3|manual) MODE=3 ;; 3|manual) MODE_SELECTION=3 ;;
4|none) MODE=4 ;; 4|none) MODE_SELECTION=4 ;;
*) say ERROR "Invalid module mode: ${CLI_MODULE_MODE}"; exit 1 ;; *) say ERROR "Invalid module mode: ${CLI_MODULE_MODE}"; exit 1 ;;
esac esac
if [ "$MODE" = "1" ]; then if [ "$MODE_SELECTION" = "1" ]; then
MODE_PRESET_NAME="$DEFAULT_PRESET_SUGGESTED" MODE_PRESET_NAME="$DEFAULT_PRESET_SUGGESTED"
elif [ "$MODE" = "2" ]; then elif [ "$MODE_SELECTION" = "2" ]; then
MODE_PRESET_NAME="$DEFAULT_PRESET_PLAYERBOTS" MODE_PRESET_NAME="$DEFAULT_PRESET_PLAYERBOTS"
fi fi
fi fi
if [ -z "$MODE" ] && [ ${#MODULE_ENABLE_SET[@]} -gt 0 ]; then if [ -z "$MODE_SELECTION" ] && [ ${#MODULE_ENABLE_SET[@]} -gt 0 ]; then
MODE=3 MODE_SELECTION=3
fi fi
if [ ${#MODULE_ENABLE_SET[@]} -gt 0 ] && [ -n "$MODE" ] && [ "$MODE" != "3" ] && [ "$MODE" != "4" ]; then if [ ${#MODULE_ENABLE_SET[@]} -gt 0 ] && [ -n "$MODE_SELECTION" ] && [ "$MODE_SELECTION" != "3" ] && [ "$MODE_SELECTION" != "4" ]; then
say INFO "Switching module preset to manual to honor --enable-modules list." say INFO "Switching module preset to manual to honor --enable-modules list."
MODE=3 MODE_SELECTION=3
fi fi
if [ "$MODE" = "4" ] && [ ${#MODULE_ENABLE_SET[@]} -gt 0 ]; then if [ "$MODE_SELECTION" = "4" ] && [ ${#MODULE_ENABLE_SET[@]} -gt 0 ]; then
say ERROR "--enable-modules cannot be used together with module-mode=none." say ERROR "--enable-modules cannot be used together with module-mode=none."
exit 1 exit 1
fi fi
local MODE_PRESET_NAME="" if [ "$MODE_SELECTION" = "preset" ] && [ -n "$CLI_MODULE_PRESET" ]; then
if [ "$MODE" = "preset" ] && [ -n "$CLI_MODULE_PRESET" ]; then
MODE_PRESET_NAME="$CLI_MODULE_PRESET" MODE_PRESET_NAME="$CLI_MODULE_PRESET"
fi fi
@@ -757,30 +839,30 @@ fi
fi fi
local max_option=$((menu_index - 1)) local max_option=$((menu_index - 1))
if [ "$NON_INTERACTIVE" = "1" ] && [ -z "$MODE" ]; then if [ "$NON_INTERACTIVE" = "1" ] && [ -z "$MODE_SELECTION" ]; then
MODE=1 MODE_SELECTION=1
fi fi
if [ -z "$MODE" ]; then if [ -z "$MODE_SELECTION" ]; then
local MODE_SELECTION local selection_input
while true; do while true; do
read -p "$(echo -e "${YELLOW}🔧 Select module configuration [1-${max_option}]: ${NC}")" MODE_SELECTION read -p "$(echo -e "${YELLOW}🔧 Select module configuration [1-${max_option}]: ${NC}")" selection_input
if [[ "$MODE_SELECTION" =~ ^[0-9]+$ ]] && [ "$MODE_SELECTION" -ge 1 ] && [ "$MODE_SELECTION" -le "$max_option" ]; then if [[ "$selection_input" =~ ^[0-9]+$ ]] && [ "$selection_input" -ge 1 ] && [ "$selection_input" -le "$max_option" ]; then
if [ -n "${MENU_PRESET_INDEX[$MODE_SELECTION]:-}" ]; then if [ -n "${MENU_PRESET_INDEX[$selection_input]:-}" ]; then
MODE="preset" MODE_SELECTION="preset"
MODE_PRESET_NAME="${MENU_PRESET_INDEX[$MODE_SELECTION]}" MODE_PRESET_NAME="${MENU_PRESET_INDEX[$selection_input]}"
else else
MODE="$MODE_SELECTION" MODE_SELECTION="$selection_input"
fi fi
break break
fi fi
say ERROR "Please select a number between 1 and ${max_option}" say ERROR "Please select a number between 1 and ${max_option}"
done done
else else
if [ "$MODE" = "preset" ]; then if [ "$MODE_SELECTION" = "preset" ]; then
say INFO "Module preset set to ${MODE_PRESET_NAME}." say INFO "Module preset set to ${MODE_PRESET_NAME}."
else else
say INFO "Module preset set to ${MODE}." say INFO "Module preset set to ${MODE_SELECTION}."
fi fi
fi fi
@@ -793,10 +875,10 @@ fi
MODULE_INSTANCE_RESET=0 MODULE_LEVEL_GRANT=0 MODULE_ASSISTANT=0 MODULE_REAGENT_BANK=0 MODULE_BLACK_MARKET_AUCTION_HOUSE=0 MODULE_ARAC=0 \ MODULE_INSTANCE_RESET=0 MODULE_LEVEL_GRANT=0 MODULE_ASSISTANT=0 MODULE_REAGENT_BANK=0 MODULE_BLACK_MARKET_AUCTION_HOUSE=0 MODULE_ARAC=0 \
MODULE_CHALLENGE_MODES=0 MODULE_OLLAMA_CHAT=0 MODULE_SKELETON_MODULE=0 MODULE_BG_SLAVERYVALLEY=0 MODULE_ELUNA_TS=0 \ MODULE_CHALLENGE_MODES=0 MODULE_OLLAMA_CHAT=0 MODULE_SKELETON_MODULE=0 MODULE_BG_SLAVERYVALLEY=0 MODULE_ELUNA_TS=0 \
MODULE_PLAYER_BOT_LEVEL_BRACKETS=0 MODULE_STATBOOSTER=0 MODULE_DUNGEON_RESPAWN=0 MODULE_AZEROTHSHARD=0 MODULE_WORGOBLIN=0 MODULE_PLAYER_BOT_LEVEL_BRACKETS=0 MODULE_STATBOOSTER=0 MODULE_DUNGEON_RESPAWN=0 MODULE_AZEROTHSHARD=0 MODULE_WORGOBLIN=0
local DEFAULT_AUTH_IMAGE_PLAYERBOTS="uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot"
local DEFAULT_WORLD_IMAGE_PLAYERBOTS="uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot"
local AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_AUTH_IMAGE_PLAYERBOTS" local AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_AUTH_IMAGE_PLAYERBOTS"
local AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_WORLD_IMAGE_PLAYERBOTS" local AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_WORLD_IMAGE_PLAYERBOTS"
local AC_AUTHSERVER_IMAGE_MODULES_VALUE="$DEFAULT_AUTH_IMAGE_MODULES"
local AC_WORLDSERVER_IMAGE_MODULES_VALUE="$DEFAULT_WORLD_IMAGE_MODULES"
local mod_var local mod_var
for mod_var in "${!MODULE_ENABLE_SET[@]}"; do for mod_var in "${!MODULE_ENABLE_SET[@]}"; do
@@ -825,13 +907,16 @@ fi
local RUN_REBUILD_NOW=$CLI_RUN_REBUILD local RUN_REBUILD_NOW=$CLI_RUN_REBUILD
local NEEDS_CXX_REBUILD=0 local NEEDS_CXX_REBUILD=0
if [ "$MODE" = "1" ]; then local module_mode_label=""
if [ "$MODE_SELECTION" = "1" ]; then
MODE_PRESET_NAME="$DEFAULT_PRESET_SUGGESTED" MODE_PRESET_NAME="$DEFAULT_PRESET_SUGGESTED"
apply_module_preset "${MODULE_PRESET_CONFIGS[$DEFAULT_PRESET_SUGGESTED]}" apply_module_preset "${MODULE_PRESET_CONFIGS[$DEFAULT_PRESET_SUGGESTED]}"
elif [ "$MODE" = "2" ]; then module_mode_label="preset 1 (Suggested)"
elif [ "$MODE_SELECTION" = "2" ]; then
MODE_PRESET_NAME="$DEFAULT_PRESET_PLAYERBOTS" MODE_PRESET_NAME="$DEFAULT_PRESET_PLAYERBOTS"
apply_module_preset "${MODULE_PRESET_CONFIGS[$DEFAULT_PRESET_PLAYERBOTS]}" apply_module_preset "${MODULE_PRESET_CONFIGS[$DEFAULT_PRESET_PLAYERBOTS]}"
elif [ "$MODE" = "3" ]; then module_mode_label="preset 2 (Playerbots + Suggested)"
elif [ "$MODE_SELECTION" = "3" ]; then
MODE_PRESET_NAME="" MODE_PRESET_NAME=""
say INFO "Answer y/n for each module" say INFO "Answer y/n for each module"
for key in "${!DISABLED_MODULE_REASONS[@]}"; do for key in "${!DISABLED_MODULE_REASONS[@]}"; do
@@ -884,7 +969,10 @@ fi
MODULE_GAIN_HONOR_GUARD=$(ask_yn "Gain Honor Guard - Honor from guard kills" "$(module_default MODULE_GAIN_HONOR_GUARD)") MODULE_GAIN_HONOR_GUARD=$(ask_yn "Gain Honor Guard - Honor from guard kills" "$(module_default MODULE_GAIN_HONOR_GUARD)")
MODULE_ARAC=$(ask_yn "All Races All Classes (requires client patch)" "$(module_default MODULE_ARAC)") MODULE_ARAC=$(ask_yn "All Races All Classes (requires client patch)" "$(module_default MODULE_ARAC)")
MODULE_WORGOBLIN=$(ask_yn "Worgoblin - Worgen & Goblin races (client patch required)" "$(module_default MODULE_WORGOBLIN)") MODULE_WORGOBLIN=$(ask_yn "Worgoblin - Worgen & Goblin races (client patch required)" "$(module_default MODULE_WORGOBLIN)")
elif [ "$MODE" = "preset" ]; then module_mode_label="preset 3 (Manual)"
elif [ "$MODE_SELECTION" = "4" ]; then
module_mode_label="preset 4 (No modules)"
elif [ "$MODE_SELECTION" = "preset" ]; then
local preset_modules="${MODULE_PRESET_CONFIGS[$MODE_PRESET_NAME]}" local preset_modules="${MODULE_PRESET_CONFIGS[$MODE_PRESET_NAME]}"
if [ -n "$preset_modules" ]; then if [ -n "$preset_modules" ]; then
apply_module_preset "$preset_modules" apply_module_preset "$preset_modules"
@@ -892,6 +980,7 @@ fi
else else
say WARNING "Preset '${MODE_PRESET_NAME}' did not contain any module selections." say WARNING "Preset '${MODE_PRESET_NAME}' did not contain any module selections."
fi fi
module_mode_label="preset (${MODE_PRESET_NAME})"
fi fi
if [ -n "$CLI_PLAYERBOT_ENABLED" ]; then if [ -n "$CLI_PLAYERBOT_ENABLED" ]; then
@@ -913,7 +1002,7 @@ fi
if [ -z "$CLI_PLAYERBOT_ENABLED" ]; then if [ -z "$CLI_PLAYERBOT_ENABLED" ]; then
PLAYERBOT_ENABLED=1 PLAYERBOT_ENABLED=1
fi fi
PLAYERBOT_MAX_BOTS=$(ask "Maximum concurrent playerbots" "${CLI_PLAYERBOT_MAX:-40}" validate_number) PLAYERBOT_MAX_BOTS=$(ask "Maximum concurrent playerbots" "${CLI_PLAYERBOT_MAX:-$DEFAULT_PLAYERBOT_MAX}" validate_number)
fi fi
for mod_var in MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE MODULE_PLAYER_BOT_LEVEL_BRACKETS MODULE_OLLAMA_CHAT MODULE_CHALLENGE_MODES MODULE_STATBOOSTER MODULE_DUNGEON_RESPAWN MODULE_SKELETON_MODULE MODULE_BG_SLAVERYVALLEY MODULE_AZEROTHSHARD MODULE_WORGOBLIN; do for mod_var in MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE MODULE_PLAYER_BOT_LEVEL_BRACKETS MODULE_OLLAMA_CHAT MODULE_CHALLENGE_MODES MODULE_STATBOOSTER MODULE_DUNGEON_RESPAWN MODULE_SKELETON_MODULE MODULE_BG_SLAVERYVALLEY MODULE_AZEROTHSHARD MODULE_WORGOBLIN; do
@@ -924,20 +1013,17 @@ fi
fi fi
done done
export NEEDS_CXX_REBUILD
if [ "$MODULE_PLAYERBOTS" = "1" ]; then if [ "$MODULE_PLAYERBOTS" = "1" ]; then
AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_AUTH_IMAGE_PLAYERBOTS" AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_AUTH_IMAGE_PLAYERBOTS"
AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_WORLD_IMAGE_PLAYERBOTS" AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_WORLD_IMAGE_PLAYERBOTS"
fi fi
local SUMMARY_MODE_TEXT local SUMMARY_MODE_TEXT="$module_mode_label"
case "$MODE" in if [ -z "$SUMMARY_MODE_TEXT" ]; then
1) SUMMARY_MODE_TEXT="preset 1 (Suggested)" ;; SUMMARY_MODE_TEXT="$MODE_SELECTION"
2) SUMMARY_MODE_TEXT="preset 2 (Playerbots + Suggested)" ;; fi
3) SUMMARY_MODE_TEXT="preset 3 (Manual)" ;;
4) SUMMARY_MODE_TEXT="preset 4 (No modules)" ;;
preset) SUMMARY_MODE_TEXT="preset (${MODE_PRESET_NAME})" ;;
*) SUMMARY_MODE_TEXT="$MODE" ;;
esac
# Summary # Summary
say HEADER "SUMMARY" say HEADER "SUMMARY"
@@ -946,6 +1032,8 @@ fi
printf " %-18s %s\n" "Storage Path:" "$STORAGE_PATH" printf " %-18s %s\n" "Storage Path:" "$STORAGE_PATH"
printf " %-18s %s\n" "Container User:" "$CONTAINER_USER" printf " %-18s %s\n" "Container User:" "$CONTAINER_USER"
printf " %-18s Daily %s:00 UTC, keep %sd/%sh\n" "Backups:" "$BACKUP_DAILY_TIME" "$BACKUP_RETENTION_DAYS" "$BACKUP_RETENTION_HOURS" printf " %-18s Daily %s:00 UTC, keep %sd/%sh\n" "Backups:" "$BACKUP_DAILY_TIME" "$BACKUP_RETENTION_DAYS" "$BACKUP_RETENTION_HOURS"
printf " %-18s %s\n" "Source checkout:" "$default_source_rel"
printf " %-18s %s\n" "Modules images:" "$AC_AUTHSERVER_IMAGE_MODULES_VALUE | $AC_WORLDSERVER_IMAGE_MODULES_VALUE"
printf " %-18s %s\n" "Modules preset:" "$SUMMARY_MODE_TEXT" printf " %-18s %s\n" "Modules preset:" "$SUMMARY_MODE_TEXT"
printf " %-18s %s\n" "Playerbot Max Bots:" "$PLAYERBOT_MAX_BOTS" printf " %-18s %s\n" "Playerbot Max Bots:" "$PLAYERBOT_MAX_BOTS"
@@ -1007,7 +1095,7 @@ fi
fi fi
local default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore" local default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore"
if [ "$MODULE_PLAYERBOTS" = "1" ]; then if [ "$NEEDS_CXX_REBUILD" = "1" ] || [ "$MODULE_PLAYERBOTS" = "1" ]; then
default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore-playerbots" default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore-playerbots"
fi fi
@@ -1034,8 +1122,10 @@ fi
MODULES_REBUILD_SOURCE_PATH_VALUE="$rebuild_source_path" MODULES_REBUILD_SOURCE_PATH_VALUE="$rebuild_source_path"
export MODULES_REBUILD_SOURCE_PATH="$MODULES_REBUILD_SOURCE_PATH_VALUE" export MODULES_REBUILD_SOURCE_PATH="$MODULES_REBUILD_SOURCE_PATH_VALUE"
if [ ! -f "$rebuild_source_path/docker-compose.yml" ]; then if [ ! -f "$rebuild_source_path/docker-compose.yml" ]; then
say INFO "Preparing source repository via scripts/setup-source.sh (git clone/fetch can take a few minutes)" say INFO "Preparing source repository via scripts/setup-source.sh (progress will stream below)"
if ! ./scripts/setup-source.sh >/dev/null 2>&1; then if ! ( set -o pipefail; ./scripts/setup-source.sh 2>&1 | while IFS= read -r line; do
say INFO "[setup-source] $line"
done ); then
say WARNING "Source setup encountered issues; running interactively." say WARNING "Source setup encountered issues; running interactively."
if ! ./scripts/setup-source.sh; then if ! ./scripts/setup-source.sh; then
say WARNING "Source setup failed; skipping automatic rebuild." say WARNING "Source setup failed; skipping automatic rebuild."
@@ -1056,9 +1146,19 @@ fi
export "$module_export_var" export "$module_export_var"
done done
# Set git config for module script # Prepare isolated git config for the module script so we do not mutate user-level settings
git config --global user.name "${GIT_USERNAME:-ac-compose}" 2>/dev/null || true local prev_git_config_global="${GIT_CONFIG_GLOBAL:-}"
git config --global user.email "${GIT_EMAIL:-noreply@azerothcore.org}" 2>/dev/null || true local git_temp_config=""
if command -v mktemp >/dev/null 2>&1; then
if ! git_temp_config="$(mktemp)"; then
git_temp_config=""
fi
fi
if [ -z "$git_temp_config" ]; then
git_temp_config="$local_modules_dir/.gitconfig.tmp"
: > "$git_temp_config"
fi
export GIT_CONFIG_GLOBAL="$git_temp_config"
# Run module staging script in local modules directory # Run module staging script in local modules directory
# Set environment variable to indicate we're running locally # Set environment variable to indicate we're running locally
@@ -1069,12 +1169,15 @@ fi
say WARNING "Module staging encountered issues, but continuing with rebuild" say WARNING "Module staging encountered issues, but continuing with rebuild"
fi fi
unset MODULES_LOCAL_RUN unset MODULES_LOCAL_RUN
fi
fi
if [ "$RUN_REBUILD_NOW" = "1" ]; then if [ -n "$git_temp_config" ]; then
if ! ./scripts/rebuild-with-modules.sh --yes --skip-stop; then rm -f "$git_temp_config"
say WARNING "Module rebuild failed; run ./scripts/rebuild-with-modules.sh manually." fi
if [ -n "$prev_git_config_global" ]; then
export GIT_CONFIG_GLOBAL="$prev_git_config_global"
else
unset GIT_CONFIG_GLOBAL
fi
fi fi
fi fi
@@ -1096,63 +1199,65 @@ fi
MODULES_REBUILD_SOURCE_PATH_VALUE="$default_source_rel" MODULES_REBUILD_SOURCE_PATH_VALUE="$default_source_rel"
fi fi
DB_PLAYERBOTS_NAME=${DB_PLAYERBOTS_NAME:-acore_playerbots} DB_PLAYERBOTS_NAME=${DB_PLAYERBOTS_NAME:-$DEFAULT_DB_PLAYERBOTS_NAME}
local CLIENT_DATA_CACHE_PATH_VALUE="${LOCAL_STORAGE_ROOT}/client-data-cache" local CLIENT_DATA_CACHE_PATH_VALUE="${LOCAL_STORAGE_ROOT}/client-data-cache"
HOST_ZONEINFO_PATH=${HOST_ZONEINFO_PATH:-/usr/share/zoneinfo} HOST_ZONEINFO_PATH=${HOST_ZONEINFO_PATH:-$DEFAULT_HOST_ZONEINFO_PATH}
MYSQL_INNODB_REDO_LOG_CAPACITY=${MYSQL_INNODB_REDO_LOG_CAPACITY:-512M} MYSQL_INNODB_REDO_LOG_CAPACITY=${MYSQL_INNODB_REDO_LOG_CAPACITY:-$DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY}
MYSQL_RUNTIME_TMPFS_SIZE=${MYSQL_RUNTIME_TMPFS_SIZE:-8G} MYSQL_RUNTIME_TMPFS_SIZE=${MYSQL_RUNTIME_TMPFS_SIZE:-$DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE}
CLIENT_DATA_VOLUME=${CLIENT_DATA_VOLUME:-ac-client-data} CLIENT_DATA_VOLUME=${CLIENT_DATA_VOLUME:-$DEFAULT_CLIENT_DATA_VOLUME}
cat > "$ENV_OUT" <<EOF cat > "$ENV_OUT" <<EOF
# Generated by ac-compose/setup.sh # Generated by ac-compose/setup.sh
COMPOSE_PROJECT_NAME=ac-compose COMPOSE_PROJECT_NAME=$DEFAULT_COMPOSE_PROJECT_NAME
STORAGE_PATH=$STORAGE_PATH STORAGE_PATH=$STORAGE_PATH
STORAGE_PATH_LOCAL=$LOCAL_STORAGE_ROOT STORAGE_PATH_LOCAL=$LOCAL_STORAGE_ROOT
HOST_ZONEINFO_PATH=$HOST_ZONEINFO_PATH HOST_ZONEINFO_PATH=${HOST_ZONEINFO_PATH:-$DEFAULT_HOST_ZONEINFO_PATH}
TZ=UTC TZ=$DEFAULT_TZ
# Database # Database
MYSQL_IMAGE=mysql:8.0 MYSQL_IMAGE=$DEFAULT_MYSQL_IMAGE
CONTAINER_MYSQL=ac-mysql CONTAINER_MYSQL=$DEFAULT_CONTAINER_MYSQL
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
MYSQL_ROOT_HOST=% MYSQL_ROOT_HOST=$DEFAULT_MYSQL_ROOT_HOST
MYSQL_USER=root MYSQL_USER=$DEFAULT_MYSQL_USER
MYSQL_PORT=3306 MYSQL_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
MYSQL_EXTERNAL_PORT=$MYSQL_EXTERNAL_PORT MYSQL_EXTERNAL_PORT=$MYSQL_EXTERNAL_PORT
MYSQL_CHARACTER_SET=utf8mb4 MYSQL_CHARACTER_SET=$DEFAULT_MYSQL_CHARACTER_SET
MYSQL_COLLATION=utf8mb4_unicode_ci MYSQL_COLLATION=$DEFAULT_MYSQL_COLLATION
MYSQL_MAX_CONNECTIONS=1000 MYSQL_MAX_CONNECTIONS=$DEFAULT_MYSQL_MAX_CONNECTIONS
MYSQL_INNODB_BUFFER_POOL_SIZE=256M MYSQL_INNODB_BUFFER_POOL_SIZE=$DEFAULT_MYSQL_INNODB_BUFFER_POOL_SIZE
MYSQL_INNODB_LOG_FILE_SIZE=64M MYSQL_INNODB_LOG_FILE_SIZE=$DEFAULT_MYSQL_INNODB_LOG_FILE_SIZE
MYSQL_INNODB_REDO_LOG_CAPACITY=$MYSQL_INNODB_REDO_LOG_CAPACITY MYSQL_INNODB_REDO_LOG_CAPACITY=${MYSQL_INNODB_REDO_LOG_CAPACITY:-$DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY}
MYSQL_RUNTIME_TMPFS_SIZE=$MYSQL_RUNTIME_TMPFS_SIZE MYSQL_RUNTIME_TMPFS_SIZE=${MYSQL_RUNTIME_TMPFS_SIZE:-$DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE}
DB_AUTH_NAME=acore_auth DB_AUTH_NAME=$DEFAULT_DB_AUTH_NAME
DB_WORLD_NAME=acore_world DB_WORLD_NAME=$DEFAULT_DB_WORLD_NAME
DB_CHARACTERS_NAME=acore_characters DB_CHARACTERS_NAME=$DEFAULT_DB_CHARACTERS_NAME
DB_PLAYERBOTS_NAME=$DB_PLAYERBOTS_NAME DB_PLAYERBOTS_NAME=${DB_PLAYERBOTS_NAME:-$DEFAULT_DB_PLAYERBOTS_NAME}
AC_DB_IMPORT_IMAGE=acore/ac-wotlk-db-import:14.0.0-dev AC_DB_IMPORT_IMAGE=$DEFAULT_AC_DB_IMPORT_IMAGE
# Services (images) # Services (images)
AC_AUTHSERVER_IMAGE=acore/ac-wotlk-authserver:14.0.0-dev AC_AUTHSERVER_IMAGE=$DEFAULT_AC_AUTHSERVER_IMAGE
AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev AC_WORLDSERVER_IMAGE=$DEFAULT_AC_WORLDSERVER_IMAGE
AC_AUTHSERVER_IMAGE_PLAYERBOTS=${AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE} AC_AUTHSERVER_IMAGE_PLAYERBOTS=${AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE}
AC_WORLDSERVER_IMAGE_PLAYERBOTS=${AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE} AC_WORLDSERVER_IMAGE_PLAYERBOTS=${AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE}
AC_AUTHSERVER_IMAGE_MODULES=${AC_AUTHSERVER_IMAGE_MODULES_VALUE}
AC_WORLDSERVER_IMAGE_MODULES=${AC_WORLDSERVER_IMAGE_MODULES_VALUE}
# Client data images # Client data images
AC_CLIENT_DATA_IMAGE=acore/ac-wotlk-client-data:14.0.0-dev AC_CLIENT_DATA_IMAGE=$DEFAULT_AC_CLIENT_DATA_IMAGE
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot AC_CLIENT_DATA_IMAGE_PLAYERBOTS=$DEFAULT_CLIENT_DATA_IMAGE_PLAYERBOTS
CLIENT_DATA_CACHE_PATH=$CLIENT_DATA_CACHE_PATH_VALUE CLIENT_DATA_CACHE_PATH=$CLIENT_DATA_CACHE_PATH_VALUE
CLIENT_DATA_VOLUME=$CLIENT_DATA_VOLUME CLIENT_DATA_VOLUME=${CLIENT_DATA_VOLUME:-$DEFAULT_CLIENT_DATA_VOLUME}
# Ports # Ports
AUTH_EXTERNAL_PORT=$AUTH_EXTERNAL_PORT AUTH_EXTERNAL_PORT=$AUTH_EXTERNAL_PORT
AUTH_PORT=3724 AUTH_PORT=$DEFAULT_AUTH_INTERNAL_PORT
WORLD_EXTERNAL_PORT=$REALM_PORT WORLD_EXTERNAL_PORT=$REALM_PORT
WORLD_PORT=8085 WORLD_PORT=$DEFAULT_WORLD_INTERNAL_PORT
SOAP_EXTERNAL_PORT=$SOAP_EXTERNAL_PORT SOAP_EXTERNAL_PORT=$SOAP_EXTERNAL_PORT
SOAP_PORT=7878 SOAP_PORT=$DEFAULT_SOAP_INTERNAL_PORT
# Realm # Realm
SERVER_ADDRESS=$SERVER_ADDRESS SERVER_ADDRESS=$SERVER_ADDRESS
@@ -1210,7 +1315,7 @@ MODULE_REAGENT_BANK=$MODULE_REAGENT_BANK
MODULE_BLACK_MARKET_AUCTION_HOUSE=$MODULE_BLACK_MARKET_AUCTION_HOUSE MODULE_BLACK_MARKET_AUCTION_HOUSE=$MODULE_BLACK_MARKET_AUCTION_HOUSE
# Client data # Client data
CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-v16} CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-$DEFAULT_CLIENT_DATA_VERSION}
# Playerbot runtime # Playerbot runtime
PLAYERBOT_ENABLED=$PLAYERBOT_ENABLED PLAYERBOT_ENABLED=$PLAYERBOT_ENABLED
@@ -1221,33 +1326,33 @@ AUTO_REBUILD_ON_DEPLOY=$AUTO_REBUILD_ON_DEPLOY
MODULES_REBUILD_SOURCE_PATH=$MODULES_REBUILD_SOURCE_PATH_VALUE MODULES_REBUILD_SOURCE_PATH=$MODULES_REBUILD_SOURCE_PATH_VALUE
# Eluna # Eluna
AC_ELUNA_ENABLED=1 AC_ELUNA_ENABLED=$DEFAULT_ELUNA_ENABLED
AC_ELUNA_TRACE_BACK=1 AC_ELUNA_TRACE_BACK=$DEFAULT_ELUNA_TRACE_BACK
AC_ELUNA_AUTO_RELOAD=1 AC_ELUNA_AUTO_RELOAD=$DEFAULT_ELUNA_AUTO_RELOAD
AC_ELUNA_BYTECODE_CACHE=1 AC_ELUNA_BYTECODE_CACHE=$DEFAULT_ELUNA_BYTECODE_CACHE
AC_ELUNA_SCRIPT_PATH=lua_scripts AC_ELUNA_SCRIPT_PATH=$DEFAULT_ELUNA_SCRIPT_PATH
AC_ELUNA_REQUIRE_PATHS= AC_ELUNA_REQUIRE_PATHS=$DEFAULT_ELUNA_REQUIRE_PATHS
AC_ELUNA_REQUIRE_CPATHS= AC_ELUNA_REQUIRE_CPATHS=$DEFAULT_ELUNA_REQUIRE_CPATHS
AC_ELUNA_AUTO_RELOAD_INTERVAL=1 AC_ELUNA_AUTO_RELOAD_INTERVAL=$DEFAULT_ELUNA_AUTO_RELOAD_INTERVAL
# Tools # Tools
PMA_HOST=ac-mysql PMA_HOST=$DEFAULT_CONTAINER_MYSQL
PMA_PORT=3306 PMA_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
PMA_USER=root PMA_USER=$DEFAULT_PMA_USER
PMA_EXTERNAL_PORT=8081 PMA_EXTERNAL_PORT=$DEFAULT_PMA_EXTERNAL_PORT
PMA_ARBITRARY=1 PMA_ARBITRARY=$DEFAULT_PMA_ARBITRARY
PMA_ABSOLUTE_URI= PMA_ABSOLUTE_URI=$DEFAULT_PMA_ABSOLUTE_URI
PMA_UPLOAD_LIMIT=300M PMA_UPLOAD_LIMIT=$DEFAULT_PMA_UPLOAD_LIMIT
PMA_MEMORY_LIMIT=512M PMA_MEMORY_LIMIT=$DEFAULT_PMA_MEMORY_LIMIT
PMA_MAX_EXECUTION_TIME=600 PMA_MAX_EXECUTION_TIME=$DEFAULT_PMA_MAX_EXECUTION_TIME
KEIRA3_EXTERNAL_PORT=4201 KEIRA3_EXTERNAL_PORT=$DEFAULT_KEIRA3_EXTERNAL_PORT
KEIRA_DATABASE_HOST=ac-mysql KEIRA_DATABASE_HOST=$DEFAULT_CONTAINER_MYSQL
KEIRA_DATABASE_PORT=3306 KEIRA_DATABASE_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
# Networking # Networking
NETWORK_NAME=azerothcore NETWORK_NAME=$DEFAULT_NETWORK_NAME
NETWORK_SUBNET=172.20.0.0/16 NETWORK_SUBNET=$DEFAULT_NETWORK_SUBNET
NETWORK_GATEWAY=172.20.0.1 NETWORK_GATEWAY=$DEFAULT_NETWORK_GATEWAY
EOF EOF
say SUCCESS ".env written to $ENV_OUT" say SUCCESS ".env written to $ENV_OUT"
@@ -1257,7 +1362,9 @@ EOF
echo "" echo ""
say HEADER "MODULE REBUILD" say HEADER "MODULE REBUILD"
if [ -n "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then if [ -n "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then
if ./scripts/rebuild-with-modules.sh --yes --source "$MODULES_REBUILD_SOURCE_PATH_VALUE"; then local rebuild_args=(--yes --skip-stop)
rebuild_args+=(--source "$MODULES_REBUILD_SOURCE_PATH_VALUE")
if ./scripts/rebuild-with-modules.sh "${rebuild_args[@]}"; then
say SUCCESS "Module rebuild completed" say SUCCESS "Module rebuild completed"
else else
say WARNING "Module rebuild failed; run ./scripts/rebuild-with-modules.sh manually once issues are resolved." say WARNING "Module rebuild failed; run ./scripts/rebuild-with-modules.sh manually once issues are resolved."