mirror of
https://github.com/azerothcore/azerothcore-wotlk.git
synced 2025-11-10 21:04:26 +08:00
Merge branch 'master' into ovv/systemd-socket-activation
This commit is contained in:
commit
2060c4cc87
@ -1,234 +0,0 @@
|
||||
########################################################################################
|
||||
# SETTINGS #
|
||||
########################################################################################
|
||||
$mysql_host = "127.0.0.1"
|
||||
$mysql_user = "export"
|
||||
$mysql_password = "export"
|
||||
$mysql_database_auth = "acore_auth"
|
||||
$mysql_database_characters = "acore_characters"
|
||||
$mysql_database_world = "acore_world"
|
||||
########################################################################################
|
||||
# SETTINGS END #
|
||||
########################################################################################
|
||||
|
||||
# Set MySQL password as temporary env var
|
||||
$env:MYSQL_PWD = $mysql_password
|
||||
|
||||
# Get the directory to sql\base directory
|
||||
$scriptDirectory = $PSScriptRoot
|
||||
$relativePath = "..\..\data\sql\base"
|
||||
$combinedPath = Join-Path -Path $scriptDirectory -ChildPath $relativePath
|
||||
$fullPath = Resolve-Path -Path $combinedPath
|
||||
|
||||
# Define the output directory (using database name)
|
||||
$output_directory_auth = "$fullPath\db_auth"
|
||||
$output_directory_characters = "$fullPath\db_characters"
|
||||
$output_directory_world = "$fullPath\db_world"
|
||||
|
||||
Write-Host " ___ _ _ ___ "
|
||||
Write-Host "/ \ ___ ___ _ _ ___ | |_ | |_ / __| ___ _ _ ___ "
|
||||
Write-Host "| - ||_ // -_)| '_|/ _ \| _|| \ | (__ / _ \| '_|/ -_)"
|
||||
Write-Host "|_|_|/__|\___||_| \___/ \__||_||_| \___|\___/|_| \___|"
|
||||
Write-Host "AzerothCore 3.3.5a - www.azerothcore.org"
|
||||
Write-Host ""
|
||||
Write-Host "Welcome to the AzerothCore Database Exporter for database squashes!"
|
||||
Write-Host ""
|
||||
Write-Host "You have configured:"
|
||||
Write-Host "Database Auth: '$mysql_database_auth'"
|
||||
Write-Host "Database Characters: '$mysql_database_characters'"
|
||||
Write-Host "Database World: '$mysql_database_world'"
|
||||
Write-Host "Output Dir Auth: '$output_directory_auth'"
|
||||
Write-Host "Output Dir Characters: '$output_directory_characters'"
|
||||
Write-Host "Output Dir World: '$output_directory_world'"
|
||||
Write-Host ""
|
||||
Write-Host "Make sure you read the entire process before you continue."
|
||||
Write-Host "https://github.com/azerothcore/azerothcore-wotlk/blob/master/data/sql/base/database-squash.md"
|
||||
Write-Host "https://github.com/azerothcore/azerothcore-wotlk/blob/master/apps/DatabaseExporter/databaseexporter.md"
|
||||
Write-Host ""
|
||||
|
||||
# Check if the user wants to continue using the tool
|
||||
do {
|
||||
$confirmation = Read-Host "Do you want to continue using the tool? (Y/N)"
|
||||
|
||||
if ($confirmation -eq 'Y' -or $confirmation -eq 'y') {
|
||||
# Continue the script
|
||||
Write-Host "AzerothCore Database Exporter starts."
|
||||
$continue = $true
|
||||
}
|
||||
elseif ($confirmation -eq 'N' -or $confirmation -eq 'n') {
|
||||
# Exit the script
|
||||
Write-Host "Exiting the AzerothCore Database Exporter."
|
||||
exit
|
||||
}
|
||||
else {
|
||||
Write-Host "Invalid input. Please enter Y or N."
|
||||
$continue = $null
|
||||
}
|
||||
} while ($continue -eq $null)
|
||||
|
||||
# Remove the output directory if it exist
|
||||
if (Test-Path $output_directory_auth) {
|
||||
Remove-Item -Path $output_directory_auth -Recurse -Force
|
||||
Write-Host "Deleted directory $output_directory_auth"
|
||||
}
|
||||
if (Test-Path $output_directory_characters) {
|
||||
Remove-Item -Path $output_directory_characters -Recurse -Force
|
||||
Write-Host "Deleted directory $output_directory_characters"
|
||||
}
|
||||
if (Test-Path $output_directory_world) {
|
||||
Remove-Item -Path $output_directory_world -Recurse -Force
|
||||
Write-Host "Deleted directory $output_directory_world"
|
||||
}
|
||||
|
||||
# Create the output directory if it doesn't exist
|
||||
if (-not (Test-Path -Path $output_directory_auth)) {
|
||||
New-Item -ItemType Directory -Force -Path $output_directory_auth
|
||||
Write-Host "Created directory $output_directory_auth"
|
||||
}
|
||||
if (-not (Test-Path -Path $output_directory_characters)) {
|
||||
New-Item -ItemType Directory -Force -Path $output_directory_characters
|
||||
Write-Host "Created directory $output_directory_characters"
|
||||
}
|
||||
if (-not (Test-Path -Path $output_directory_world)) {
|
||||
New-Item -ItemType Directory -Force -Path $output_directory_world
|
||||
Write-Host "Created directory $output_directory_world"
|
||||
}
|
||||
|
||||
# Fix for dumping TIMESTAMP data
|
||||
$timezone = "+01:00"
|
||||
$mysqlCommand = "SET time_zone = '$timezone';"
|
||||
$mysqlExec = "mysql -h $mysql_host -u $mysql_user -p$mysql_password -e `"$mysqlCommand`""
|
||||
Invoke-Expression -Command $mysqlExec
|
||||
|
||||
# PS script uses non-utf-8 encoding by default
|
||||
# https://stackoverflow.com/a/58438716
|
||||
# Save the current encoding and switch to UTF-8.
|
||||
$prev = [Console]::OutputEncoding
|
||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "#########################################################"
|
||||
Write-Host "EXPORT AUTH DATABASE START"
|
||||
Write-Host "#########################################################"
|
||||
Write-Host ""
|
||||
Write-Host "Please enter your password for user '$mysql_user'"
|
||||
|
||||
# Export Auth Database
|
||||
# Connect to MySQL and get all the tables
|
||||
$tables_auth = mysql -h $mysql_host -u $mysql_user -D $mysql_database_auth -e "SHOW TABLES;" | Select-Object -Skip 1
|
||||
# Iterate through each table and export both the structure and contents into the same SQL file
|
||||
foreach ($table in $tables_auth) {
|
||||
# Define the output file path for this table
|
||||
$output_file = "$output_directory_auth\$table.sql"
|
||||
|
||||
# Clear the content of the output file if it exists, or create a new one
|
||||
if (Test-Path $output_file) {
|
||||
Clear-Content -Path $output_file
|
||||
}
|
||||
|
||||
# Export the table structure (CREATE TABLE) and table data (INSERT) to the SQL file
|
||||
$create_table_command = "mysqldump -h $mysql_host -u $mysql_user --skip-tz-utc $mysql_database_auth $table"
|
||||
$create_table_output = Invoke-Expression -Command $create_table_command
|
||||
# write file with utf-8 encoding
|
||||
# https://stackoverflow.com/a/32951824
|
||||
[IO.File]::WriteAllLines($output_file, $create_table_output)
|
||||
|
||||
# Format the INSERT values to be on seperate lines.
|
||||
$content = Get-Content -Raw $output_file
|
||||
$formattedContent = $content -replace 'VALUES \(', "VALUES`r`n("
|
||||
$formattedContent = $formattedContent -replace '\),', "),`r`n"
|
||||
$formattedContent | Set-Content $output_file
|
||||
|
||||
Write-Host "Exported structure and data for table $table to $output_file"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "#########################################################"
|
||||
Write-Host "EXPORT AUTH DATABASE END"
|
||||
Write-Host "#########################################################"
|
||||
Write-Host ""
|
||||
Write-Host "#########################################################"
|
||||
Write-Host "EXPORT CHARACTERS DATABASE START"
|
||||
Write-Host "#########################################################"
|
||||
Write-Host ""
|
||||
Write-Host "Please enter your password for user '$mysql_user'"
|
||||
|
||||
# Export Characters Database
|
||||
# Connect to MySQL and get all the tables
|
||||
$tables_characters = mysql -h $mysql_host -u $mysql_user -D $mysql_database_characters -e "SHOW TABLES;" | Select-Object -Skip 1
|
||||
# Iterate through each table and export both the structure and contents into the same SQL file
|
||||
foreach ($table in $tables_characters) {
|
||||
# Define the output file path for this table
|
||||
$output_file = "$output_directory_characters\$table.sql"
|
||||
|
||||
# Clear the content of the output file if it exists, or create a new one
|
||||
if (Test-Path $output_file) {
|
||||
Clear-Content -Path $output_file
|
||||
}
|
||||
|
||||
# Export the table structure (CREATE TABLE) and table data (INSERT) to the SQL file
|
||||
$create_table_command = "mysqldump -h $mysql_host -u $mysql_user --skip-tz-utc $mysql_database_characters $table"
|
||||
$create_table_output = Invoke-Expression -Command $create_table_command
|
||||
# write file with utf-8 encoding
|
||||
# https://stackoverflow.com/a/32951824
|
||||
[IO.File]::WriteAllLines($output_file, $create_table_output)
|
||||
|
||||
# Format the INSERT values to be on seperate lines.
|
||||
$content = Get-Content -Raw $output_file
|
||||
$formattedContent = $content -replace 'VALUES \(', "VALUES`r`n("
|
||||
$formattedContent = $formattedContent -replace '\),', "),`r`n"
|
||||
$formattedContent | Set-Content $output_file
|
||||
|
||||
Write-Host "Exported structure and data for table $table to $output_file"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "#########################################################"
|
||||
Write-Host "EXPORT CHARACTERS DATABASE END"
|
||||
Write-Host "#########################################################"
|
||||
Write-Host ""
|
||||
Write-Host "#########################################################"
|
||||
Write-Host "EXPORT WORLD DATABASE START"
|
||||
Write-Host "#########################################################"
|
||||
Write-Host ""
|
||||
Write-Host "Please enter your password for user '$mysql_user'"
|
||||
|
||||
# Export World Database
|
||||
# Connect to MySQL and get all the tables
|
||||
$tables_world = mysql -h $mysql_host -u $mysql_user -D $mysql_database_world -e "SHOW TABLES;" | Select-Object -Skip 1
|
||||
# Iterate through each table and export both the structure and contents into the same SQL file
|
||||
foreach ($table in $tables_world) {
|
||||
# Define the output file path for this table
|
||||
$output_file = "$output_directory_world\$table.sql"
|
||||
|
||||
# Clear the content of the output file if it exists, or create a new one
|
||||
if (Test-Path $output_file) {
|
||||
Clear-Content -Path $output_file
|
||||
}
|
||||
|
||||
# Export the table structure (CREATE TABLE) and table data (INSERT) to the SQL file
|
||||
$create_table_command = "mysqldump -h $mysql_host -u $mysql_user --skip-tz-utc $mysql_database_world $table"
|
||||
$create_table_output = Invoke-Expression -Command $create_table_command
|
||||
# write file with utf-8 encoding
|
||||
# https://stackoverflow.com/a/32951824
|
||||
[IO.File]::WriteAllLines($output_file, $create_table_output)
|
||||
|
||||
# Format the INSERT values to be on seperate lines.
|
||||
$content = Get-Content -Raw $output_file
|
||||
$formattedContent = $content -replace 'VALUES \(', "VALUES`r`n("
|
||||
$formattedContent = $formattedContent -replace '\),', "),`r`n"
|
||||
$formattedContent | Set-Content $output_file
|
||||
|
||||
Write-Host "Exported structure and data for table $table to $output_file"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "#########################################################"
|
||||
Write-Host "EXPORT WORLD DATABASE END"
|
||||
Write-Host "#########################################################"
|
||||
Write-Host ""
|
||||
Write-Host "Database Exporter completed."
|
||||
Write-Host "Have a nice day :)"
|
||||
|
||||
# Restore the previous encoding.
|
||||
[Console]::OutputEncoding = $prev
|
||||
@ -1,85 +0,0 @@
|
||||
# The AzerothCore Database Exporter for Database Squashes
|
||||
|
||||
> [!CAUTION]
|
||||
> These steps are only for project maintainers who intend to update base files.
|
||||
|
||||
## Manual setting updates
|
||||
|
||||
Update the settings in `DatabaseExporter.ps1` to reflect your setup by opening it with your preffered text editor.
|
||||
|
||||
> [!NOTE]
|
||||
> Only update the settings within the SETTINGS block.
|
||||
|
||||
These are the default settings:
|
||||
```ps
|
||||
########################################################################################
|
||||
# SETTINGS #
|
||||
########################################################################################
|
||||
$mysql_host = "127.0.0.1"
|
||||
$mysql_user = "export"
|
||||
$mysql_password = "export"
|
||||
$mysql_database_auth = "acore_auth"
|
||||
$mysql_database_characters = "acore_characters"
|
||||
$mysql_database_world = "acore_world"
|
||||
########################################################################################
|
||||
# SETTINGS END #
|
||||
########################################################################################
|
||||
```
|
||||
|
||||
## Description of the tool
|
||||
|
||||
This tool updates the base files automatically. Hence, it must run from this directory.
|
||||
|
||||
This is how it works step-by-step:
|
||||
|
||||
1. Check that all paths look correct.
|
||||
2. Accept to continue using the tool.
|
||||
3. The tool will delete the `db_auth` `db_characters` `db_world` directories in `..\..\data\sql\base\`
|
||||
4. The tool will create the `db_auth` `db_characters` `db_world` directories in `..\..\data\sql\base\`
|
||||
5. The tool will export the `db_auth` table into `..\..\data\sql\base\db_auth\`
|
||||
6. The tool will export the `db_characters` table into `..\..\data\sql\base\db_characters\`
|
||||
7. The tool will export the `db_world` table into `..\..\data\sql\base\db_world\`
|
||||
|
||||
## Run the tool
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This tool CAN NOT be moved outside this directory. If you do it will create files in the wrong places.
|
||||
|
||||
1. Make sure you have MySQL installed on your system and that the mysqldump tool is accessible by your PATH system variable. If it is not set you will encounter errors.
|
||||
|
||||
- Go into System Variables
|
||||
- Open the PATH variable
|
||||
- Add the path to your $\MySQL Server\bin\ - e.g. C:\Program Files\MySQL\MySQL Server 8.4\bin\
|
||||
|
||||
2. If you haven't run PowerShell scripts before, you'll need to adjust the execution policy.
|
||||
|
||||
- Open PowerShell as an Administrator.
|
||||
- Run the following command to allow running scripts:
|
||||
```ps
|
||||
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
```
|
||||
- This allows scripts to run on your system, but they need to be locally created or downloaded from trusted sources.
|
||||
|
||||
3. Open PowerShell (PS)
|
||||
|
||||
- Press Win + X and select Windows PowerShell (Admin) / Terminal (Admin)
|
||||
|
||||
4. Navigate to the script
|
||||
|
||||
- In PS, use the `cd` command to change the directory
|
||||
```ps
|
||||
cd "C:\AzerothCore\apps\DatabaseExporter"
|
||||
```
|
||||
|
||||
5. Run the script
|
||||
|
||||
- In PS, run the script
|
||||
```ps
|
||||
.\DatabaseExporter.ps1
|
||||
```
|
||||
|
||||
6. Follow the instructions given by the tool.
|
||||
|
||||
7. Now refer back to the database-squash.md instructions. (Located in ..\..\data\sql\base\)
|
||||
|
||||
Completed :)
|
||||
69
apps/DatabaseSquash/DatabaseExporter/DatabaseExporter.sh
Normal file
69
apps/DatabaseSquash/DatabaseExporter/DatabaseExporter.sh
Normal file
@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
if [[ "$PROJECT_ROOT" =~ ^/([a-zA-Z])/(.*) ]]; then
|
||||
DRIVE_LETTER="${BASH_REMATCH[1]}"
|
||||
PATH_REMAINDER="${BASH_REMATCH[2]}"
|
||||
PROJECT_ROOT="${DRIVE_LETTER^^}:/${PATH_REMAINDER}"
|
||||
fi
|
||||
|
||||
BASE_OUTPUT_DIR="$PROJECT_ROOT/data/sql/base"
|
||||
|
||||
read -p "Enter MySQL username: " DB_USER
|
||||
read -p "Enter MySQL password: " DB_PASS
|
||||
read -p "Enter MySQL host (default: localhost): " DB_HOST
|
||||
DB_HOST=${DB_HOST:-localhost}
|
||||
read -p "Enter MySQL port (default: 3306): " DB_PORT
|
||||
DB_PORT=${DB_PORT:-3306}
|
||||
|
||||
# Prompt for database names
|
||||
read -p "Enter name of Auth database [default: acore_auth]: " DB_AUTH
|
||||
DB_AUTH=${DB_AUTH:-acore_auth}
|
||||
read -p "Enter name of Characters database [default: acore_characters]: " DB_CHARACTERS
|
||||
DB_CHARACTERS=${DB_CHARACTERS:-acore_characters}
|
||||
read -p "Enter name of World database [default: acore_world]: " DB_WORLD
|
||||
DB_WORLD=${DB_WORLD:-acore_world}
|
||||
|
||||
# Mapping for folder names
|
||||
declare -A DB_MAP=(
|
||||
["$DB_AUTH"]="db_auth"
|
||||
["$DB_CHARACTERS"]="db_characters"
|
||||
["$DB_WORLD"]="db_world"
|
||||
)
|
||||
|
||||
# Dump each database
|
||||
for DB_NAME in "${!DB_MAP[@]}"; do
|
||||
FOLDER_NAME="${DB_MAP[$DB_NAME]}"
|
||||
echo "📦 Dumping database '$DB_NAME' into folder '$FOLDER_NAME'"
|
||||
echo "$BASE_OUTPUT_DIR/$FOLDER_NAME"
|
||||
mkdir -p "$BASE_OUTPUT_DIR/$FOLDER_NAME"
|
||||
|
||||
TABLES=$(mysql -u "$DB_USER" -p"$DB_PASS" -h "$DB_HOST" -P "$DB_PORT" -N -e "SHOW TABLES FROM \`$DB_NAME\`;")
|
||||
|
||||
if [[ -z "$TABLES" ]]; then
|
||||
echo "⚠️ No tables found or failed to connect to '$DB_NAME'. Skipping."
|
||||
continue
|
||||
fi
|
||||
|
||||
while IFS= read -r raw_table; do
|
||||
TABLE=$(echo "$raw_table" | tr -d '\r"' | xargs)
|
||||
if [[ -n "$TABLE" ]]; then
|
||||
echo " ➤ Dumping table: $TABLE"
|
||||
mysqldump -u $DB_USER -p$DB_PASS -h $DB_HOST -P $DB_PORT --extended-insert $DB_NAME $TABLE > $BASE_OUTPUT_DIR/$FOLDER_NAME/$TABLE.sql
|
||||
|
||||
# cleanup files
|
||||
sed -E '
|
||||
s/VALUES[[:space:]]*/VALUES\n/;
|
||||
:a
|
||||
s/\),\(/\),\n\(/g;
|
||||
ta
|
||||
' "$BASE_OUTPUT_DIR/$FOLDER_NAME/$TABLE.sql" > "$BASE_OUTPUT_DIR/$FOLDER_NAME/${TABLE}_formatted.sql"
|
||||
mv "$BASE_OUTPUT_DIR/$FOLDER_NAME/${TABLE}_formatted.sql" "$BASE_OUTPUT_DIR/$FOLDER_NAME/$TABLE.sql"
|
||||
fi
|
||||
done <<< "$TABLES"
|
||||
done
|
||||
|
||||
echo "✅ Done dumping all specified databases."
|
||||
16
apps/DatabaseSquash/DatabaseExporter/databaseexporter.md
Normal file
16
apps/DatabaseSquash/DatabaseExporter/databaseexporter.md
Normal file
@ -0,0 +1,16 @@
|
||||
# The AzerothCore Database Exporter for Database Squashes
|
||||
|
||||
> [!CAUTION]
|
||||
> These steps are only for project maintainers who intend to update base files.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. MySQL
|
||||
2. mysqldump
|
||||
|
||||
## Usage
|
||||
|
||||
1. Run DatabaseExporter.sh from the current directory.
|
||||
2. Fill in required data within the CLI.
|
||||
3. The tool will autopopulate the basefile directories.
|
||||
4. Done.
|
||||
52
apps/DatabaseSquash/DatabaseSquash.sh
Normal file
52
apps/DatabaseSquash/DatabaseSquash.sh
Normal file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "❗CAUTION"
|
||||
echo "This tool is only supposed to be used by AzerothCore Maintainers."
|
||||
echo "The tool is used to prepare for, and generate a database squash."
|
||||
echo
|
||||
echo "Before you continue make sure you have read"
|
||||
echo "https://github.com/azerothcore/azerothcore-wotlk/blob/master/data/sql/base/database-squash.md"
|
||||
echo
|
||||
read -p "Are you sure you want to continue (Y/N)?" choice
|
||||
case "$choice" in
|
||||
y|Y ) echo "Starting...";;
|
||||
* ) echo "Aborted"; exit 0 ;;
|
||||
esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
if [[ "$PROJECT_ROOT" =~ ^/([a-zA-Z])/(.*) ]]; then
|
||||
DRIVE_LETTER="${BASH_REMATCH[1]}"
|
||||
PATH_REMAINDER="${BASH_REMATCH[2]}"
|
||||
PROJECT_ROOT="${DRIVE_LETTER^^}:/${PATH_REMAINDER}"
|
||||
fi
|
||||
|
||||
VERSION_UPDATER_PATH="$PROJECT_ROOT/apps/DatabaseSquash/VersionUpdater/versionupdater.sh"
|
||||
|
||||
"$VERSION_UPDATER_PATH"
|
||||
|
||||
echo "✅ VersionUpdater Completed..."
|
||||
echo
|
||||
echo "❗IMPORTANT!"
|
||||
echo "1. Before you continue you need to drop all your databases."
|
||||
echo "2. Run WorldServer to populate the database."
|
||||
echo
|
||||
echo "❗DO NOT continue before you have completed the steps above!"
|
||||
echo
|
||||
echo "The next step will export your database and overwrite the base files."
|
||||
echo
|
||||
read -p "Are you sure you want to export your database (Y/N)?" choice
|
||||
case "$choice" in
|
||||
y|Y ) echo "Starting...";;
|
||||
* ) echo "Aborted"; exit 0 ;;
|
||||
esac
|
||||
|
||||
DATABASE_EXPORTER_PATH="$PROJECT_ROOT/apps/DatabaseSquash/DatabaseExporter/databaseexporter.sh"
|
||||
|
||||
"$DATABASE_EXPORTER_PATH"
|
||||
|
||||
echo "✅ DatabaseExporter Completed..."
|
||||
echo "✅ DatabaseSquash Completed... "
|
||||
echo
|
||||
read -p "Press Enter to exit..."
|
||||
84
apps/DatabaseSquash/VersionUpdater/VersionUpdater.sh
Normal file
84
apps/DatabaseSquash/VersionUpdater/VersionUpdater.sh
Normal file
@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
if [[ "$PROJECT_ROOT" =~ ^/([a-zA-Z])/(.*) ]]; then
|
||||
DRIVE_LETTER="${BASH_REMATCH[1]}"
|
||||
PATH_REMAINDER="${BASH_REMATCH[2]}"
|
||||
PROJECT_ROOT="${DRIVE_LETTER^^}:/${PATH_REMAINDER}"
|
||||
fi
|
||||
|
||||
ACORE_JSON_PATH="$PROJECT_ROOT/acore.json"
|
||||
DB_WORLD_UPDATE_DIR="$PROJECT_ROOT/data/sql/updates/db_world"
|
||||
|
||||
VERSION_LINE=$(grep '"version"' "$ACORE_JSON_PATH")
|
||||
VERSION=$(echo "$VERSION_LINE" | sed -E 's/.*"version": *"([^"]+)".*/\1/')
|
||||
|
||||
# Parse version into parts
|
||||
if [[ "$VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(.*)$ ]]; then
|
||||
MAJOR="${BASH_REMATCH[1]}"
|
||||
SUFFIX="${BASH_REMATCH[4]}"
|
||||
NEW_VERSION="$((MAJOR + 1)).0.0$SUFFIX"
|
||||
|
||||
# Replace version in file
|
||||
sed -i.bak -E "s/(\"version\": *\")[^\"]+(\" *)/\1$NEW_VERSION\2/" "$ACORE_JSON_PATH"
|
||||
rm -f "$ACORE_JSON_PATH.bak"
|
||||
|
||||
echo "✅ Version updated to $NEW_VERSION"
|
||||
else
|
||||
echo "Error: Could not parse version string: $VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the new major version from NEW_VERSION
|
||||
if [[ "$NEW_VERSION" =~ ^([0-9]+)\. ]]; then
|
||||
NEW_MAJOR="${BASH_REMATCH[1]}"
|
||||
else
|
||||
echo "Error: Unable to extract major version from $NEW_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prepare SQL content
|
||||
DB_VERSION_CONTENT="'ACDB 335.${NEW_MAJOR}-dev'"
|
||||
SQL_QUERY="UPDATE \`version\` SET \`db_version\`=${DB_VERSION_CONTENT}, \`cache_id\`=${NEW_MAJOR} LIMIT 1;"
|
||||
|
||||
# Format date as yyyy_mm_dd
|
||||
TODAY=$(date +%Y_%m_%d)
|
||||
|
||||
# Ensure directory exists
|
||||
mkdir -p "$DB_WORLD_UPDATE_DIR"
|
||||
|
||||
# List existing files for today
|
||||
existing_files=($(find "$DB_WORLD_UPDATE_DIR" -maxdepth 1 -type f -name "${TODAY}_*.sql" 2>/dev/null))
|
||||
|
||||
# Determine next xx counter
|
||||
# Determine next xx
|
||||
COUNTER="00"
|
||||
if [ ${#existing_files[@]} -gt 0 ]; then
|
||||
max=0
|
||||
for file in "${existing_files[@]}"; do
|
||||
basename=$(basename "$file")
|
||||
if [[ "$basename" =~ ^${TODAY}_([0-9]{2})\.sql$ ]]; then
|
||||
num=${BASH_REMATCH[1]}
|
||||
if [[ "$num" =~ ^[0-9]+$ ]] && (( 10#$num > max )); then
|
||||
max=$((10#$num))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
COUNTER=$(printf "%02d" $((max + 1)))
|
||||
fi
|
||||
|
||||
# Compose final file path
|
||||
SQL_FILENAME="${TODAY}_${COUNTER}.sql"
|
||||
SQL_FILE_PATH="$DB_WORLD_UPDATE_DIR/$SQL_FILENAME"
|
||||
|
||||
# Write to file
|
||||
{
|
||||
echo "-- Auto-generated by VersionUpdater.sh on $(date)"
|
||||
echo "$SQL_QUERY"
|
||||
} > "$SQL_FILE_PATH"
|
||||
|
||||
echo "✅ SQL file created at $SQL_FILE_PATH"
|
||||
10
apps/DatabaseSquash/VersionUpdater/versionupdater.md
Normal file
10
apps/DatabaseSquash/VersionUpdater/versionupdater.md
Normal file
@ -0,0 +1,10 @@
|
||||
# The AzerothCore Version Updater for Database Squashes
|
||||
|
||||
> [!CAUTION]
|
||||
> These steps are only for project maintainers who intend to update base files.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Run VersionUpdater.sh from the current directory.
|
||||
2. The tool will update acore.json and create a new update sql file.
|
||||
3. Done.
|
||||
11
apps/DatabaseSquash/databasesquash.md
Normal file
11
apps/DatabaseSquash/databasesquash.md
Normal file
@ -0,0 +1,11 @@
|
||||
# The AzerothCore DatabaseSquash tool for Database Squashes
|
||||
|
||||
> [!CAUTION]
|
||||
> These steps are only for project maintainers who intend to update base files.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Run DatabaseSquash.sh from the current directory.
|
||||
2. The tool will run VersionUpdater.sh and DatabaseExporter.sh
|
||||
3. Follow the instructions in the CLI.
|
||||
4. Done.
|
||||
@ -1,132 +0,0 @@
|
||||
# Get the directory to acore.json
|
||||
$scriptDirectory = $PSScriptRoot
|
||||
$relativePath = "..\.."
|
||||
$combinedPath = Join-Path -Path $scriptDirectory -ChildPath $relativePath
|
||||
$fullPath = Resolve-Path -Path $combinedPath
|
||||
$jsonFilePath = "$fullPath\acore.json"
|
||||
# Get the directory for SQL update
|
||||
$relativePathDbWorldUpdate = "..\..\data\sql\updates\db_world"
|
||||
$combinedPathDbWorldUpdate = Join-Path -Path $scriptDirectory -ChildPath $relativePathDbWorldUpdate
|
||||
$fullPathDbWorldUpdate = Resolve-Path -Path $combinedPathDbWorldUpdate
|
||||
|
||||
Write-Host " ___ _ _ ___ "
|
||||
Write-Host "/ \ ___ ___ _ _ ___ | |_ | |_ / __| ___ _ _ ___ "
|
||||
Write-Host "| - ||_ // -_)| '_|/ _ \| _|| \ | (__ / _ \| '_|/ -_)"
|
||||
Write-Host "|_|_|/__|\___||_| \___/ \__||_||_| \___|\___/|_| \___|"
|
||||
Write-Host "AzerothCore 3.3.5a - www.azerothcore.org"
|
||||
Write-Host ""
|
||||
Write-Host "Welcome to the AzerothCore Version Updater for database squashes!"
|
||||
Write-Host ""
|
||||
Write-Host "You have configured:"
|
||||
Write-Host "acore.json Path: '$jsonFilePath'"
|
||||
Write-Host "World SQL Updates path: '$fullPathDbWorldUpdate'"
|
||||
Write-Host ""
|
||||
Write-Host "Make sure you read the entire process before you continue."
|
||||
Write-Host "https://github.com/azerothcore/azerothcore-wotlk/blob/master/data/sql/base/database-squash.md"
|
||||
Write-Host "https://github.com/azerothcore/azerothcore-wotlk/blob/master/apps/VersionUpdater/versionupdater.md"
|
||||
Write-Host ""
|
||||
|
||||
# Check if the user wants to continue using the tool
|
||||
do {
|
||||
$confirmation = Read-Host "Do you want to continue using the tool? (Y/N)"
|
||||
|
||||
if ($confirmation -eq 'Y' -or $confirmation -eq 'y') {
|
||||
# Continue the script
|
||||
Write-Host "AzerothCore Version Updater starts."
|
||||
Write-Host ""
|
||||
$continue = $true
|
||||
}
|
||||
elseif ($confirmation -eq 'N' -or $confirmation -eq 'n') {
|
||||
# Exit the script
|
||||
Write-Host "Exiting the AzerothCore Version Updater."
|
||||
exit
|
||||
}
|
||||
else {
|
||||
Write-Host "Invalid input. Please enter Y or N."
|
||||
$continue = $null
|
||||
}
|
||||
} while ($continue -eq $null)
|
||||
|
||||
# Read the JSON file and convert it to a PowerShell object
|
||||
$jsonContent = Get-Content -Path $jsonFilePath | ConvertFrom-Json
|
||||
|
||||
# Get the current version
|
||||
$currentVersion = $jsonContent.version
|
||||
|
||||
# Match version components (major.minor.patch and optional suffix like -dev or -alpha)
|
||||
if ($currentVersion -match '(\d+)\.(\d+)\.(\d+)(-.*)?') {
|
||||
$major = $matches[1]
|
||||
$minor = $matches[2]
|
||||
$patch = $matches[3]
|
||||
$suffix = $matches[4]
|
||||
|
||||
# Increment the major version
|
||||
$major = [int]$major + 1
|
||||
|
||||
# Reset minor and patch version to 0 (if incrementing major)
|
||||
$minor = 0
|
||||
$patch = 0
|
||||
|
||||
# Reassemble the version with the suffix if it exists
|
||||
$newVersion = "$major.$minor.$patch$suffix"
|
||||
|
||||
# Update the version in the JSON object
|
||||
$jsonContent.version = $newVersion
|
||||
} else {
|
||||
Write-Host "Unknown error in $jsonFilePath. Exiting."
|
||||
exit
|
||||
}
|
||||
|
||||
# Convert the updated object back to JSON format
|
||||
$newJsonContent = $jsonContent | ConvertTo-Json -Depth 3
|
||||
|
||||
# Write the updated content back to the file
|
||||
$newJsonContent | Set-Content -Path $jsonFilePath
|
||||
|
||||
Write-Host "acore.json version updated to $newVersion"
|
||||
|
||||
# Create the SQL Version update file.
|
||||
# Get today's date in the format YYYY_MM_DD
|
||||
$today = Get-Date -Format "yyyy_MM_dd"
|
||||
|
||||
# Get the list of files in the directory that match the pattern "YYYY_MM_DD_versionNumber.sql"
|
||||
$existingFiles = Get-ChildItem -Path $fullPathDbWorldUpdate -Filter "$today*_*.sql"
|
||||
|
||||
# If no files exist for today, start with version number 00
|
||||
if ($existingFiles.Count -eq 0) {
|
||||
[int]$newVersionNumber = 0
|
||||
} else {
|
||||
# Extract the version number from the existing files (e.g., YYYY_MM_DD_versionNumber.sql)
|
||||
$maxVersionNumber = $existingFiles | ForEach-Object {
|
||||
if ($_ -match "$today_(\d{2})\.sql") {
|
||||
[int]$matches[1]
|
||||
}
|
||||
} | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum
|
||||
|
||||
# Increment the version number by 1
|
||||
[int]$newVersionNumber = $maxVersionNumber + 1
|
||||
}
|
||||
|
||||
# Format the new version number as a two-digit number (e.g., 01, 02, etc.)
|
||||
$formattedVersionNumber = $newVersionNumber.ToString("D2")
|
||||
|
||||
# Define the new filename using the date and incremented version number
|
||||
$newFileName = "$today" + "_$formattedVersionNumber.sql"
|
||||
$newFilePath = Join-Path -Path $fullPathDbWorldUpdate -ChildPath $newFileName
|
||||
|
||||
# Define the SQL content to write to the file
|
||||
$tableName = '`version`'
|
||||
$db_version = '`db_version`'
|
||||
$db_version_content = "'ACDB 335.$major-dev'"
|
||||
$cache_id = '`cache_id`'
|
||||
$sqlContent = "UPDATE $tableName SET $db_version=$db_version_content, $cache_id=$major LIMIT 1;"
|
||||
|
||||
# Write the content to the new SQL file
|
||||
$sqlContent | Set-Content -Path $newFilePath
|
||||
|
||||
Write-Host "SQL file created: $newFilePath"
|
||||
Write-Host "SQL content: $sqlContent"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Version Updater completed."
|
||||
Write-Host "Have a nice day :)"
|
||||
@ -1,53 +0,0 @@
|
||||
# The AzerothCore Version Updater for Database Squashes
|
||||
|
||||
> [!CAUTION]
|
||||
> These steps are only for project maintainers who intend to update base files.
|
||||
|
||||
## Description of the tool
|
||||
|
||||
This tool updates the version in DB and acore.json automatically. Hence, it must run from this directory.
|
||||
|
||||
This is how it works step-by-step:
|
||||
|
||||
1. Check that all paths look correct.
|
||||
2. Accept to continue using the tool.
|
||||
3. The tool will update the acore.json file and increment it by 1.
|
||||
4. The tool will create a file with the proper UPDATE for world database in `..\..\data\sql\updates\db_world`.
|
||||
|
||||
## Run the tool
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This tool CAN NOT be moved outside this directory. If you do it will create files in the wrong places.
|
||||
|
||||
1. If you haven't run PowerShell scripts before, you'll need to adjust the execution policy.
|
||||
|
||||
- Open PowerShell as an Administrator.
|
||||
- Run the following command to allow running scripts:
|
||||
```ps
|
||||
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
```
|
||||
- This allows scripts to run on your system, but they need to be locally created or downloaded from trusted sources.
|
||||
|
||||
2. Open PowerShell (PS)
|
||||
|
||||
- Press Win + X and select Windows PowerShell (Admin) / Terminal (Admin)
|
||||
|
||||
3. Navigate to the script
|
||||
|
||||
- In PS, use the `cd` command to change the directory
|
||||
```ps
|
||||
cd "C:\AzerothCore\apps\VersionUpdater"
|
||||
```
|
||||
|
||||
4. Run the script
|
||||
|
||||
- In PS, run the script
|
||||
```ps
|
||||
.\VersionUpdater.ps1
|
||||
```
|
||||
|
||||
5. Follow the instructions given by the tool.
|
||||
|
||||
6. Now refer back to the database-squash.md instructions. (Located in ..\..\data\sql\base\)
|
||||
|
||||
Completed :)
|
||||
@ -3,12 +3,22 @@ import os
|
||||
import sys
|
||||
import re
|
||||
import glob
|
||||
import subprocess
|
||||
|
||||
base_dir = os.getcwd()
|
||||
|
||||
# Get the pending directory of the project
|
||||
base_dir = os.getcwd()
|
||||
pattern = os.path.join(base_dir, 'data/sql/updates/pending_db_*')
|
||||
src_directory = glob.glob(pattern)
|
||||
|
||||
# Get files from base dir
|
||||
base_pattern = os.path.join(base_dir, 'data/sql/base/db_*')
|
||||
base_directory = glob.glob(base_pattern)
|
||||
|
||||
# Get files from archive dir
|
||||
archive_pattern = os.path.join(base_dir, 'data/sql/archive/db_*')
|
||||
archive_directory = glob.glob(archive_pattern)
|
||||
|
||||
# Global variables
|
||||
error_handler = False
|
||||
results = {
|
||||
@ -17,7 +27,8 @@ results = {
|
||||
"SQL codestyle check": "Passed",
|
||||
"INSERT & DELETE safety usage check": "Passed",
|
||||
"Missing semicolon check": "Passed",
|
||||
"Backtick check": "Passed"
|
||||
"Backtick check": "Passed",
|
||||
"Directory check": "Passed"
|
||||
}
|
||||
|
||||
# Collect all files in all directories
|
||||
@ -30,6 +41,24 @@ def collect_files_from_directories(directories: list) -> list:
|
||||
all_files.append(os.path.join(root, file))
|
||||
return all_files
|
||||
|
||||
# Used to find changed or added files compared to master.
|
||||
def get_changed_files() -> list:
|
||||
subprocess.run(["git", "fetch", "origin", "master"], check=True)
|
||||
result = subprocess.run(
|
||||
["git", "diff", "--name-status", "origin/master"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
changed_files = []
|
||||
for line in result.stdout.strip().splitlines():
|
||||
if not line:
|
||||
continue
|
||||
status, path = line.split(maxsplit=1)
|
||||
if status in ("A", "M"):
|
||||
changed_files.append(path)
|
||||
return changed_files
|
||||
|
||||
# Main function to parse all the files of the project
|
||||
def parsing_file(files: list) -> None:
|
||||
print("Starting AzerothCore SQL Codestyle check...")
|
||||
@ -38,19 +67,32 @@ def parsing_file(files: list) -> None:
|
||||
print("https://www.azerothcore.org/wiki/sql-standards")
|
||||
print(" ")
|
||||
|
||||
# Iterate over all files
|
||||
# Iterate over all files in data/sql/updates/pending_db_*
|
||||
for file_path in files:
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
multiple_blank_lines_check(file, file_path)
|
||||
trailing_whitespace_check(file, file_path)
|
||||
sql_check(file, file_path)
|
||||
insert_delete_safety_check(file, file_path)
|
||||
semicolon_check(file, file_path)
|
||||
backtick_check(file, file_path)
|
||||
except UnicodeDecodeError:
|
||||
print(f"\n❌ Could not decode file {file_path}")
|
||||
sys.exit(1)
|
||||
if "base" not in file_path and "archive" not in file_path:
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
multiple_blank_lines_check(file, file_path)
|
||||
trailing_whitespace_check(file, file_path)
|
||||
sql_check(file, file_path)
|
||||
insert_delete_safety_check(file, file_path)
|
||||
semicolon_check(file, file_path)
|
||||
backtick_check(file, file_path)
|
||||
except UnicodeDecodeError:
|
||||
print(f"\n❌ Could not decode file {file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
# Make sure we only check changed or added files when we work with base/archive paths
|
||||
changed_files = get_changed_files()
|
||||
# Iterate over all file paths
|
||||
for file_path in changed_files:
|
||||
if "base" in file_path or "archive" in file_path:
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
directory_check(f, file_path)
|
||||
except UnicodeDecodeError:
|
||||
print(f"\n❌ Could not decode file {file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
# Output the results
|
||||
print("\n ")
|
||||
@ -172,11 +214,6 @@ def semicolon_check(file: io, file_path: str) -> None:
|
||||
file.seek(0) # Reset file pointer to the start
|
||||
check_failed = False
|
||||
|
||||
sql_statement_regex = re.compile(r'^\s*(SELECT|INSERT|UPDATE|DELETE|REPLACE|SET)\b', re.IGNORECASE)
|
||||
block_comment_start = re.compile(r'/\*')
|
||||
block_comment_end = re.compile(r'\*/')
|
||||
inline_comment = re.compile(r'--.*')
|
||||
|
||||
query_open = False
|
||||
in_block_comment = False
|
||||
inside_values_block = False
|
||||
@ -323,8 +360,31 @@ def backtick_check(file: io, file_path: str) -> None:
|
||||
error_handler = True
|
||||
results["Backtick check"] = "Failed"
|
||||
|
||||
def directory_check(file: io, file_path: str) -> None:
|
||||
global error_handler, results
|
||||
file.seek(0)
|
||||
check_failed = False
|
||||
|
||||
# Normalize path and split into parts
|
||||
normalized_path = os.path.normpath(file_path) # handles / and \
|
||||
path_parts = normalized_path.split(os.sep)
|
||||
|
||||
# Fail if '/base/' is part of the path
|
||||
if "base" in path_parts:
|
||||
print(f"❗ {file_path} is changed/added in the base directory.\nIf this is intended, please notify a maintainer.")
|
||||
check_failed = True
|
||||
|
||||
# Fail if '/archive/' is part of the path
|
||||
if "archive" in path_parts:
|
||||
print(f"❗ {file_path} is changed/added in the archive directory.\nIf this is intended, please notify a maintainer.")
|
||||
check_failed = True
|
||||
|
||||
if check_failed:
|
||||
error_handler = True
|
||||
results["Directory check"] = "Failed"
|
||||
|
||||
# Collect all files from matching directories
|
||||
all_files = collect_files_from_directories(src_directory)
|
||||
all_files = collect_files_from_directories(src_directory) + collect_files_from_directories(base_directory) + collect_files_from_directories(archive_directory)
|
||||
|
||||
# Main function
|
||||
parsing_file(all_files)
|
||||
|
||||
1
apps/db_exporter/.gitignore
vendored
1
apps/db_exporter/.gitignore
vendored
@ -1 +0,0 @@
|
||||
config.sh
|
||||
@ -1,12 +0,0 @@
|
||||
This script is used by devs to export the databases to base directories
|
||||
|
||||
You should use it on clean databases
|
||||
|
||||
## USAGE
|
||||
|
||||
NOTE: this script is only working under unix currently
|
||||
|
||||
1) You must create a config.sh file changing DB connection configurations
|
||||
of /conf/config.sh.dist
|
||||
|
||||
2) Run the db_export.sh script and wait
|
||||
@ -1,52 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ROOTPATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../" && pwd )"
|
||||
|
||||
source "$ROOTPATH/apps/bash_shared/includes.sh"
|
||||
|
||||
if [ -f "./config.sh" ]; then
|
||||
source "./config.sh" # should overwrite previous
|
||||
fi
|
||||
|
||||
echo "This is a dev-only procedure to export the DB into the SQL base files. All base files will be overwritten."
|
||||
read -p "Are you sure you want to continue (y/N)? " choice
|
||||
case "$choice" in
|
||||
y|Y ) echo "Exporting the DB into the SQL base files...";;
|
||||
* ) return;;
|
||||
esac
|
||||
|
||||
echo "===== STARTING PROCESS ====="
|
||||
|
||||
|
||||
function export() {
|
||||
echo "Working on: "$1
|
||||
database=$1
|
||||
|
||||
var_base_path="DB_"$database"_PATHS"
|
||||
base_path=${!var_base_path%/}
|
||||
|
||||
base_conf="TPATH="$base_path";\
|
||||
CLEANFOLDER=1; \
|
||||
CHMODE=0; \
|
||||
TEXTDUMPS=0; \
|
||||
PARSEDUMP=1; \
|
||||
FULL=0; \
|
||||
DUMPOPTS='--skip-comments --skip-set-charset --routines --extended-insert --order-by-primary --single-transaction --quick'; \
|
||||
"
|
||||
|
||||
var_base_conf="DB_"$database"_CONF"
|
||||
base_conf=$base_conf${!var_base_conf}
|
||||
|
||||
var_base_name="DB_"$database"_NAME"
|
||||
base_name=${!var_base_name}
|
||||
|
||||
|
||||
bash "$AC_PATH_DEPS/acore/mysql-tools/mysql-tools" "dump" "" "$base_name" "" "$base_conf"
|
||||
}
|
||||
|
||||
for db in ${DATABASES[@]}
|
||||
do
|
||||
export "$db"
|
||||
done
|
||||
|
||||
echo "===== DONE ====="
|
||||
@ -3,23 +3,18 @@ New process around handling database squashes since https://github.com/azerothco
|
||||
> [!CAUTION]
|
||||
> These steps are only for project maintainers who intend to update base files.
|
||||
|
||||
How to do the squash.
|
||||
## Requirements
|
||||
|
||||
1. MySQL
|
||||
2. mysqldump
|
||||
|
||||
## Usage
|
||||
|
||||
> [!IMPORTANT]
|
||||
> A squash needs to be done on a clean database. Drop all tables in Auth, Characters and World.
|
||||
|
||||
1. Update the acore.json and DB version by running VersionUpdater.ps1 (Located in ..\apps\VersionUpdater\)
|
||||
|
||||
> [!NOTE]
|
||||
> Read the versionupdater.md file to use it properly.
|
||||
|
||||
2. Drop all your databases, and run Worldserver to populate a clean database.
|
||||
3. Export the databases using the DatabaseExporter.ps1 (Located in ..\apps\DatabaseExporter\)
|
||||
|
||||
> [!NOTE]
|
||||
> Read the databaseexporter.md file to use it properly.
|
||||
|
||||
6. Make a PR
|
||||
1. Run DatabaseSquash.sh (Located in ..\apps\DatabaseSquash\)
|
||||
2. Make a PR
|
||||
|
||||
> [!IMPORTANT]
|
||||
> No DB PRs should be merged during this process!
|
||||
|
||||
7
data/sql/updates/db_world/2025_06_27_00.sql
Normal file
7
data/sql/updates/db_world/2025_06_27_00.sql
Normal file
@ -0,0 +1,7 @@
|
||||
-- DB update 2025_06_21_03 -> 2025_06_27_00
|
||||
-- Bound Fire Elemental
|
||||
UPDATE `creature_template` SET `dmgschool` = 2, `spell_school_immune_mask` = 4 WHERE `entry` IN (30416, 31453);
|
||||
-- Bound Water Elemental
|
||||
UPDATE `creature_template` SET `dmgschool` = 4, `spell_school_immune_mask` = 16 WHERE `entry` IN (30419, 31454);
|
||||
-- Bound Air Elemental
|
||||
UPDATE `creature_template` SET `dmgschool` = 3, `spell_school_immune_mask` = 8 WHERE `entry` IN (30418, 31452);
|
||||
9
data/sql/updates/db_world/2025_06_27_01.sql
Normal file
9
data/sql/updates/db_world/2025_06_27_01.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- DB update 2025_06_27_00 -> 2025_06_27_01
|
||||
--
|
||||
DELETE FROM `acore_string` WHERE `entry` = 288;
|
||||
INSERT INTO `acore_string` (`entry`,`content_default`) VALUES (288,'Cannot go to spawn {} as only {} exist');
|
||||
|
||||
UPDATE `command` SET `help`='Syntax: .go creature id #creature_entry [#spawn] Teleports you to first (if no #spawn provided) spawn the given creature entry. ' WHERE `name` = 'go creature id';
|
||||
|
||||
DELETE FROM `command` WHERE `name` = 'go gameobject id';
|
||||
INSERT INTO `command` VALUES('go gameobject id',1,'Syntax: .go gameobject id #gameobject_entry [#spawn] Teleports you to first (if no #spawn provided) spawn the given gameobject entry.');
|
||||
2
data/sql/updates/db_world/2025_06_27_02.sql
Normal file
2
data/sql/updates/db_world/2025_06_27_02.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- DB update 2025_06_27_01 -> 2025_06_27_02
|
||||
UPDATE `command` SET `help`='Syntax: .account create $account $password $email\r\n\r\nCreate account and set password to it.\r\n$email is optional, can be left blank.' WHERE `name`='account create';
|
||||
64
data/sql/updates/db_world/2025_06_28_00.sql
Normal file
64
data/sql/updates/db_world/2025_06_28_00.sql
Normal file
@ -0,0 +1,64 @@
|
||||
-- DB update 2025_06_27_02 -> 2025_06_28_00
|
||||
|
||||
-- Remove respawn time for Citizens of Havenshire (Not needed)
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (-128919, -128967, -128918, -128965, -128917, -128964, -128915, -128963, -128962, -128914, -128913, -128961, -128960, -128912, -128911, -128959, -128922, -128979, -128927, -128986, -128928, -128970, -128930, -128966, -128973, -128924, -128976, -128954, -128978, -128929, -128980, -128934, -128981, -128926, -128968, -128920, -128993, -128916, -128991, -128935, -128992, -128948, -128958, -128910)) AND (`id` IN (8));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(-128919, 0, 8, 0, 109, 0, 100, 0, 0, 12896700, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896700 Finished - Despawn In 2000 ms'),
|
||||
(-128967, 0, 8, 0, 109, 0, 100, 0, 0, 12896700, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896700 Finished - Despawn In 2000 ms'),
|
||||
(-128918, 0, 8, 0, 109, 0, 100, 0, 0, 12896500, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896500 Finished - Despawn In 2000 ms'),
|
||||
(-128965, 0, 8, 0, 109, 0, 100, 0, 0, 12896500, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896500 Finished - Despawn In 2000 ms'),
|
||||
(-128917, 0, 8, 0, 109, 0, 100, 0, 0, 12896400, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896400 Finished - Despawn In 2000 ms'),
|
||||
(-128964, 0, 8, 0, 109, 0, 100, 0, 0, 12896400, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896400 Finished - Despawn In 2000 ms'),
|
||||
(-128915, 0, 8, 0, 109, 0, 100, 0, 0, 12896300, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896300 Finished - Despawn In 2000 ms'),
|
||||
(-128963, 0, 8, 0, 109, 0, 100, 0, 0, 12896300, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896300 Finished - Despawn In 2000 ms'),
|
||||
(-128962, 0, 8, 0, 109, 0, 100, 0, 0, 12896200, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896200 Finished - Despawn In 2000 ms'),
|
||||
(-128914, 0, 8, 0, 109, 0, 100, 0, 0, 12896200, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896200 Finished - Despawn In 2000 ms'),
|
||||
(-128913, 0, 8, 0, 109, 0, 100, 0, 0, 12896100, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896100 Finished - Despawn In 2000 ms'),
|
||||
(-128961, 0, 8, 0, 109, 0, 100, 0, 0, 12896100, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896100 Finished - Despawn In 2000 ms'),
|
||||
(-128960, 0, 8, 0, 109, 0, 100, 0, 0, 12896000, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896000 Finished - Despawn In 2000 ms'),
|
||||
(-128912, 0, 8, 0, 109, 0, 100, 0, 0, 12896000, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896000 Finished - Despawn In 2000 ms'),
|
||||
(-128911, 0, 8, 0, 109, 0, 100, 0, 0, 12895900, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12895900 Finished - Despawn In 2000 ms'),
|
||||
(-128959, 0, 8, 0, 109, 0, 100, 0, 0, 12895900, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12895900 Finished - Despawn In 2000 ms'),
|
||||
(-128922, 0, 8, 0, 109, 0, 100, 0, 0, 12892200, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12892200 Finished - Despawn In 2000 ms'),
|
||||
(-128979, 0, 8, 0, 109, 0, 100, 0, 0, 12892200, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12892200 Finished - Despawn In 2000 ms'),
|
||||
(-128927, 0, 8, 0, 109, 0, 100, 0, 0, 12892700, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12892700 Finished - Despawn In 2000 ms'),
|
||||
(-128986, 0, 8, 0, 109, 0, 100, 0, 0, 12892700, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12892700 Finished - Despawn In 2000 ms'),
|
||||
(-128928, 0, 8, 0, 109, 0, 100, 0, 0, 12892800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12892800 Finished - Despawn In 2000 ms'),
|
||||
(-128970, 0, 8, 0, 109, 0, 100, 0, 0, 12892800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12892800 Finished - Despawn In 2000 ms'),
|
||||
(-128930, 0, 8, 0, 109, 0, 100, 0, 0, 12893000, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12893000 Finished - Despawn In 2000 ms'),
|
||||
(-128966, 0, 8, 0, 109, 0, 100, 0, 0, 12893000, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12893000 Finished - Despawn In 2000 ms'),
|
||||
(-128973, 0, 8, 0, 109, 0, 100, 0, 0, 12897300, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12897300 Finished - Despawn In 2000 ms'),
|
||||
(-128924, 0, 8, 0, 109, 0, 100, 0, 0, 12897300, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12897300 Finished - Despawn In 2000 ms'),
|
||||
(-128976, 0, 8, 0, 109, 0, 100, 0, 0, 12897600, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12897600 Finished - Despawn In 2000 ms'),
|
||||
(-128954, 0, 8, 0, 109, 0, 100, 0, 0, 12897600, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12897600 Finished - Despawn In 2000 ms'),
|
||||
(-128978, 0, 8, 0, 109, 0, 100, 0, 0, 12897800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12897800 Finished - Despawn In 2000 ms'),
|
||||
(-128929, 0, 8, 0, 109, 0, 100, 0, 0, 12897800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12897800 Finished - Despawn In 2000 ms'),
|
||||
(-128980, 0, 8, 0, 109, 0, 100, 0, 0, 12898000, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12898000 Finished - Despawn In 2000 ms'),
|
||||
(-128934, 0, 8, 0, 109, 0, 100, 0, 0, 12898000, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12898000 Finished - Despawn In 2000 ms'),
|
||||
(-128981, 0, 8, 0, 109, 0, 100, 0, 0, 12898100, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12898100 Finished - Despawn In 2000 ms'),
|
||||
(-128926, 0, 8, 0, 109, 0, 100, 0, 0, 12898100, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12898100 Finished - Despawn In 2000 ms'),
|
||||
(-128968, 0, 8, 0, 109, 0, 100, 0, 0, 12896800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896800 Finished - Despawn In 2000 ms'),
|
||||
(-128920, 0, 8, 0, 109, 0, 100, 0, 0, 12896800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12896800 Finished - Despawn In 2000 ms'),
|
||||
(-128993, 0, 8, 0, 109, 0, 100, 0, 0, 12899300, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12899300 Finished - Despawn In 2000 ms'),
|
||||
(-128916, 0, 8, 0, 109, 0, 100, 0, 0, 12899300, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12899300 Finished - Despawn In 2000 ms'),
|
||||
(-128991, 0, 8, 0, 109, 0, 100, 0, 0, 12899100, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12899100 Finished - Despawn In 2000 ms'),
|
||||
(-128935, 0, 8, 0, 109, 0, 100, 0, 0, 12899100, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12899100 Finished - Despawn In 2000 ms'),
|
||||
(-128992, 0, 8, 0, 109, 0, 100, 0, 0, 12899200, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12899200 Finished - Despawn In 2000 ms'),
|
||||
(-128948, 0, 8, 0, 109, 0, 100, 0, 0, 12899200, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12899200 Finished - Despawn In 2000 ms'),
|
||||
(-128958, 0, 8, 0, 109, 0, 100, 0, 0, 12895800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12895800 Finished - Despawn In 2000 ms'),
|
||||
(-128910, 0, 8, 0, 109, 0, 100, 0, 0, 12895800, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Citizen of Havenshire - On Path 12895800 Finished - Despawn In 2000 ms');
|
||||
|
||||
-- Remove Respawn Time for Stallions/Mares/Colts (Not needed)
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = -129215);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(-129215, 0, 2, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 232, 12921500, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Respawn - Start Path 12921500'),
|
||||
(-129215, 0, 3, 4, 109, 0, 100, 0, 0, 12921500, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 4, 5, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129236, 28606, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 5, 6, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129246, 28607, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 6, 7, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129249, 28607, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 7, 8, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129251, 28607, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 8, 9, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129248, 28607, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 9, 10, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129245, 28607, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 10, 11, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129214, 28605, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 11, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 10, 129235, 28606, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Path 12921500 Finished - Despawn In 2000 ms'),
|
||||
(-129215, 0, 12, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Havenshire Stallion - On Reset - Set Active On');
|
||||
4
data/sql/updates/db_world/2025_06_29_00.sql
Normal file
4
data/sql/updates/db_world/2025_06_29_00.sql
Normal file
@ -0,0 +1,4 @@
|
||||
-- DB update 2025_06_28_00 -> 2025_06_29_00
|
||||
--
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id` = 29313 AND `ScriptName` = 'spell_gen_cooldown_all';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (29313 , 'spell_gen_cooldown_all');
|
||||
2
data/sql/updates/db_world/2025_06_29_01.sql
Normal file
2
data/sql/updates/db_world/2025_06_29_01.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- DB update 2025_06_29_00 -> 2025_06_29_01
|
||||
UPDATE `creature_template` SET `unit_flags` = `unit_flags` | 256 WHERE `entry` = 23741;
|
||||
6
data/sql/updates/db_world/2025_06_29_02.sql
Normal file
6
data/sql/updates/db_world/2025_06_29_02.sql
Normal file
@ -0,0 +1,6 @@
|
||||
-- DB update 2025_06_29_01 -> 2025_06_29_02
|
||||
--
|
||||
DELETE FROM `acore_string` WHERE `entry` IN (1184,1185);
|
||||
INSERT INTO `acore_string` (`entry`, `content_default`) VALUES
|
||||
(1184, '| Guild Ranks:'),
|
||||
(1185, '| {} - {}');
|
||||
3
data/sql/updates/db_world/2025_06_29_03.sql
Normal file
3
data/sql/updates/db_world/2025_06_29_03.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- DB update 2025_06_29_02 -> 2025_06_29_03
|
||||
--
|
||||
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_chapter5_rebuke' AND `spell_id` = 53680;
|
||||
6
data/sql/updates/db_world/2025_06_30_00.sql
Normal file
6
data/sql/updates/db_world/2025_06_30_00.sql
Normal file
@ -0,0 +1,6 @@
|
||||
-- DB update 2025_06_29_03 -> 2025_06_30_00
|
||||
--
|
||||
DELETE FROM `acore_string` WHERE `entry` IN (6617, 6618);
|
||||
INSERT INTO `acore_string` (`entry`, `content_default`) VALUES
|
||||
(6617, 'GM Spectator is ON'),
|
||||
(6618, 'GM Spectator is OFF');
|
||||
@ -78,7 +78,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_REP_REALM_CHARACTERS, "REPLACE INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, reg_mail, email, joindate) VALUES(?, ?, ?, ?, ?, ?, NOW())", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC);
|
||||
|
||||
@ -193,6 +193,9 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
|
||||
{
|
||||
DefaultTargetSelector targetSelector(me, spellInfo->GetMaxRange(false), false, true, 0);
|
||||
target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* target) {
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
@ -225,6 +228,9 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
|
||||
|
||||
DefaultTargetSelector defaultTargetSelector(me, range, false, true, -(int32)spellId);
|
||||
auto targetSelector = [&](Unit* target) {
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
|
||||
@ -165,9 +165,10 @@ struct PowerUsersSelector : public Acore::unary_function<Unit*, bool>
|
||||
}
|
||||
};
|
||||
|
||||
struct FarthestTargetSelector : public Acore::unary_function<Unit*, bool>
|
||||
// Simple selector based on range and Los
|
||||
struct RangeSelector : public Acore::unary_function<Unit*, bool>
|
||||
{
|
||||
FarthestTargetSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {}
|
||||
RangeSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {}
|
||||
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
|
||||
@ -2506,12 +2506,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT:
|
||||
{
|
||||
std::vector<uint32> waypoints;
|
||||
std::copy_if(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(),
|
||||
std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
|
||||
|
||||
float distanceToClosest = std::numeric_limits<float>::max();
|
||||
WayPoint* closestWp = nullptr;
|
||||
uint32 closestWpId = 0;
|
||||
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
@ -2519,29 +2515,34 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
if (IsSmart(creature))
|
||||
{
|
||||
for (uint32 wp : waypoints)
|
||||
for (uint32 wp = e.action.startClosestWaypoint.pathId1; wp <= e.action.startClosestWaypoint.pathId2; ++wp)
|
||||
{
|
||||
WPPath* path = sSmartWaypointMgr->GetPath(wp);
|
||||
if (!path || path->empty())
|
||||
continue;
|
||||
|
||||
auto itrWp = path->find(0);
|
||||
auto itrWp = path->find(1);
|
||||
if (itrWp != path->end())
|
||||
{
|
||||
if (WayPoint* wp = itrWp->second)
|
||||
if (WayPoint* wpData = itrWp->second)
|
||||
{
|
||||
float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z);
|
||||
float distToThisPath = creature->GetExactDistSq(wpData->x, wpData->y, wpData->z);
|
||||
if (distToThisPath < distanceToClosest)
|
||||
{
|
||||
distanceToClosest = distToThisPath;
|
||||
closestWp = wp;
|
||||
closestWpId = wp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closestWp)
|
||||
CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true);
|
||||
if (closestWpId)
|
||||
{
|
||||
bool repeat = e.action.startClosestWaypoint.repeat;
|
||||
bool run = e.action.startClosestWaypoint.run;
|
||||
|
||||
CAST_AI(SmartAI, creature->AI())->StartPath(repeat, closestWpId, run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3515,7 +3516,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
case SMART_TARGET_FARTHEST:
|
||||
if (me)
|
||||
{
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist)))
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -806,7 +806,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_REMOVE_POWER: return sizeof(SmartAction::power);
|
||||
case SMART_ACTION_GAME_EVENT_STOP: return sizeof(SmartAction::gameEventStop);
|
||||
case SMART_ACTION_GAME_EVENT_START: return sizeof(SmartAction::gameEventStart);
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::closestWaypointFromList);
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::startClosestWaypoint);
|
||||
case SMART_ACTION_RISE_UP: return sizeof(SmartAction::moveRandom);
|
||||
case SMART_ACTION_RANDOM_SOUND: return sizeof(SmartAction::randomSound);
|
||||
case SMART_ACTION_SET_CORPSE_DELAY: return sizeof(SmartAction::corpseDelay);
|
||||
@ -1536,15 +1536,22 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT:
|
||||
{
|
||||
if (e.action.startClosestWaypoint.pathId1 == 0 || e.action.startClosestWaypoint.pathId2 == 0 || e.action.startClosestWaypoint.pathId2 < e.action.startClosestWaypoint.pathId1)
|
||||
{
|
||||
if (std::all_of(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), [](uint32 wp) { return wp == 0; }))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid pathId1 or pathId2, it must be greater than 0 and pathId1 > pathId2",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
if (e.action.startClosestWaypoint.repeat > 1 || e.action.startClosestWaypoint.run > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid run ({}) or repeat ({}) parameter, must be 0 or 1.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(),
|
||||
e.action.startClosestWaypoint.repeat, e.action.startClosestWaypoint.run);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_INVOKER_CAST:
|
||||
if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type))
|
||||
{
|
||||
|
||||
@ -1284,8 +1284,11 @@ struct SmartAction
|
||||
|
||||
struct
|
||||
{
|
||||
std::array<uint32, SMART_ACTION_PARAM_COUNT> wps;
|
||||
} closestWaypointFromList;
|
||||
uint32 pathId1;
|
||||
uint32 pathId2;
|
||||
uint32 repeat;
|
||||
uint32 run;
|
||||
} startClosestWaypoint;
|
||||
|
||||
struct
|
||||
{
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
namespace AccountMgr
|
||||
{
|
||||
|
||||
AccountOpResult CreateAccount(std::string username, std::string password)
|
||||
AccountOpResult CreateAccount(std::string username, std::string password, std::string email /*= ""*/)
|
||||
{
|
||||
if (utf8length(username) > MAX_ACCOUNT_STR)
|
||||
return AOR_NAME_TOO_LONG; // username's too long
|
||||
@ -35,8 +35,12 @@ namespace AccountMgr
|
||||
if (utf8length(password) > MAX_PASS_STR)
|
||||
return AOR_PASS_TOO_LONG; // password's too long
|
||||
|
||||
if (utf8length(email) > MAX_EMAIL_STR)
|
||||
return AOR_EMAIL_TOO_LONG; // email is too long
|
||||
|
||||
Utf8ToUpperOnlyLatin(username);
|
||||
Utf8ToUpperOnlyLatin(password);
|
||||
Utf8ToUpperOnlyLatin(email);
|
||||
|
||||
if (GetId(username))
|
||||
return AOR_NAME_ALREADY_EXIST; // username does already exist
|
||||
@ -48,6 +52,8 @@ namespace AccountMgr
|
||||
stmt->SetData(1, salt);
|
||||
stmt->SetData(2, verifier);
|
||||
stmt->SetData(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION)));
|
||||
stmt->SetData(4, email);
|
||||
stmt->SetData(5, email);
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ enum AccountOpResult
|
||||
|
||||
namespace AccountMgr
|
||||
{
|
||||
AccountOpResult CreateAccount(std::string username, std::string password);
|
||||
AccountOpResult CreateAccount(std::string username, std::string password, std::string email = "");
|
||||
AccountOpResult DeleteAccount(uint32 accountId);
|
||||
AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword);
|
||||
AccountOpResult ChangePassword(uint32 accountId, std::string newPassword);
|
||||
|
||||
@ -788,9 +788,7 @@ void Creature::Update(uint32 diff)
|
||||
m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveBackwardsMovementTime -= diff;
|
||||
}
|
||||
|
||||
// Circling the target
|
||||
if (diff >= m_moveCircleMovementTime)
|
||||
@ -799,9 +797,17 @@ void Creature::Update(uint32 diff)
|
||||
m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveCircleMovementTime -= diff;
|
||||
|
||||
// Periodically check if able to move, if not, extend leash timer
|
||||
if (diff >= m_extendLeashTime)
|
||||
{
|
||||
if (!CanFreeMove())
|
||||
UpdateLeashExtensionTime();
|
||||
m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL;
|
||||
}
|
||||
else
|
||||
m_extendLeashTime -= diff;
|
||||
}
|
||||
|
||||
// Call for assistance if not disabled
|
||||
|
||||
@ -396,8 +396,10 @@ public:
|
||||
bool IsFreeToMove();
|
||||
static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000;
|
||||
static constexpr uint32 MOVE_BACKWARDS_CHECK_INTERVAL = 2000;
|
||||
static constexpr uint32 EXTEND_LEASH_CHECK_INTERVAL = 3000;
|
||||
uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
|
||||
uint32 m_moveBackwardsMovementTime = MOVE_BACKWARDS_CHECK_INTERVAL;
|
||||
uint32 m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL;
|
||||
|
||||
[[nodiscard]] bool HasSwimmingFlagOutOfCombat() const
|
||||
{
|
||||
|
||||
@ -10002,6 +10002,16 @@ void Player::RemoveSpellMods(Spell* spell)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// ROGUE MUTILATE WITH COLD BLOOD
|
||||
if (spellInfo->Id == 5374)
|
||||
{
|
||||
SpellInfo const* sp = mod->ownerAura->GetSpellInfo();
|
||||
if (sp->Id == 14177) // Cold Blood
|
||||
{
|
||||
mod->charges = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE))
|
||||
itr = m_spellMods[i].begin();
|
||||
@ -13631,7 +13641,11 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass());
|
||||
if (!rcEntry)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character {} has skill {} that does not exist.", GetGUID().ToString(), skill);
|
||||
LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) that is invalid for the race/class combination (Race: {}, Class: {}). Will be deleted.",
|
||||
GetName(), GetGUID().GetCounter(), skill, getRace(), getClass());
|
||||
|
||||
// Mark skill for deletion in the database
|
||||
mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(0, SKILL_DELETED)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -13652,7 +13666,8 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character {} has skill {} with value 0. Will be deleted.", GetGUID().ToString(), skill);
|
||||
LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) with value 0. Will be deleted.",
|
||||
GetName(), GetGUID().GetCounter(), skill);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL);
|
||||
|
||||
|
||||
@ -597,6 +597,7 @@ enum PlayerExtraFlags
|
||||
PLAYER_EXTRA_SPECTATOR_ON = 0x0080, // Marks if player is spectactor
|
||||
PLAYER_EXTRA_PVP_DEATH = 0x0100, // store PvP death status until corpse creating.
|
||||
PLAYER_EXTRA_SHOW_DK_PET = 0x0400, // Marks if player should see ghoul on login screen
|
||||
PLAYER_EXTRA_GM_SPECTATOR = 0x0800,
|
||||
};
|
||||
|
||||
// 2^n values
|
||||
@ -1177,6 +1178,9 @@ public:
|
||||
void SetGameMaster(bool on);
|
||||
[[nodiscard]] bool isGMChat() const { return m_ExtraFlags & PLAYER_EXTRA_GM_CHAT; }
|
||||
void SetGMChat(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_GM_CHAT; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_CHAT; }
|
||||
[[nodiscard]] bool IsGMSpectator() const { return m_ExtraFlags & PLAYER_EXTRA_GM_SPECTATOR; }
|
||||
void SetGMSpectator(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_GM_SPECTATOR; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_SPECTATOR; }
|
||||
|
||||
[[nodiscard]] bool isTaxiCheater() const { return m_ExtraFlags & PLAYER_EXTRA_TAXICHEAT; }
|
||||
void SetTaxiCheater(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_TAXICHEAT; else m_ExtraFlags &= ~PLAYER_EXTRA_TAXICHEAT; }
|
||||
[[nodiscard]] bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); }
|
||||
|
||||
@ -20791,6 +20791,10 @@ void Unit::PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPoi
|
||||
{
|
||||
valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction()));
|
||||
}
|
||||
else if (target->IsGMSpectator() && IsControlledByPlayer())
|
||||
{
|
||||
valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction()));
|
||||
}
|
||||
}
|
||||
|
||||
sScriptMgr->OnPatchValuesUpdate(this, valuesUpdateBuf, posPointers, target);
|
||||
|
||||
@ -331,7 +331,8 @@ enum AcoreStrings
|
||||
LANG_COMMAND_WHISPERON = 285,
|
||||
LANG_COMMAND_WHISPEROFF = 286,
|
||||
LANG_COMMAND_CREATGUIDNOTFOUND = 287,
|
||||
// TICKET STRINGS NEED REWRITE // 288-296 FREE
|
||||
LANG_COMMAND_GONOTENOUGHSPAWNS = 288,
|
||||
// TICKET STRINGS NEED REWRITE // 289-296 FREE
|
||||
|
||||
// END
|
||||
LANG_COMMAND_WANDER_DISTANCE = 297,
|
||||
@ -971,7 +972,9 @@ enum AcoreStrings
|
||||
LANG_GUILD_INFO_BANK_GOLD = 1181,
|
||||
LANG_GUILD_INFO_MOTD = 1182,
|
||||
LANG_GUILD_INFO_EXTRA_INFO = 1183,
|
||||
// Room for more level 3 1184-1198 not used
|
||||
LANG_GUILD_INFO_RANKS = 1184,
|
||||
LANG_GUILD_INFO_RANKS_LIST = 1185,
|
||||
// Room for more level 3 1186-1198 not used
|
||||
|
||||
// Debug commands
|
||||
LANG_DO_NOT_USE_6X_DEBUG_AREATRIGGER_LEFT = 1999,
|
||||
@ -1168,8 +1171,10 @@ enum AcoreStrings
|
||||
LANG_GM_ANNOUNCE_COLOR = 6615,
|
||||
|
||||
LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852
|
||||
LANG_GM_SPECTATOR_ON = 6617,
|
||||
LANG_GM_SPECTATOR_OFF = 6618,
|
||||
|
||||
// Free strings 6617-7522
|
||||
// Free strings 6619-7522
|
||||
|
||||
LANG_WORLD_CLOSED = 7523,
|
||||
LANG_WORLD_OPENED = 7524,
|
||||
|
||||
@ -153,18 +153,20 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
MovementInform(owner);
|
||||
}
|
||||
|
||||
if (owner->movespline->Finalized())
|
||||
{ // Mobs should chase you infinitely if you stop and wait every few seconds.
|
||||
i_leashExtensionTimer.Update(time_diff);
|
||||
if (i_leashExtensionTimer.Passed())
|
||||
{
|
||||
i_leashExtensionTimer.Reset(5000);
|
||||
if (cOwner)
|
||||
if (cOwner)
|
||||
{
|
||||
if (owner->movespline->Finalized() && cOwner->IsWithinMeleeRange(target))
|
||||
{ // Mobs should chase you infinitely if you stop and wait every few seconds.
|
||||
i_leashExtensionTimer.Update(time_diff);
|
||||
if (i_leashExtensionTimer.Passed())
|
||||
{
|
||||
i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK));
|
||||
cOwner->UpdateLeashExtensionTime();
|
||||
}
|
||||
}
|
||||
else if (i_recalculateTravel)
|
||||
i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK));
|
||||
}
|
||||
else if (i_recalculateTravel)
|
||||
i_leashExtensionTimer.Reset(5000);
|
||||
|
||||
// if the target moved, we have to consider whether to adjust
|
||||
if (!_lastTargetPosition || target->GetPosition() != _lastTargetPosition.value() || mutualChase != _mutualChase || !owner->IsWithinLOSInMap(target))
|
||||
@ -298,6 +300,7 @@ void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner)
|
||||
i_path = nullptr;
|
||||
_lastTargetPosition.reset();
|
||||
i_recheckDistance.Reset(0);
|
||||
i_leashExtensionTimer.Reset(owner->GetAttackTime(BASE_ATTACK));
|
||||
owner->SetWalk(false);
|
||||
owner->AddUnitState(UNIT_STATE_CHASE);
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
class AchievementGlobalMgr;
|
||||
class AchievementMgr;
|
||||
class ArenaTeam;
|
||||
class AuctionEntry;
|
||||
class AuctionHouseMgr;
|
||||
class AuctionHouseObject;
|
||||
class Aura;
|
||||
@ -98,6 +97,7 @@ enum WeatherState : uint32;
|
||||
struct AchievementCriteriaEntry;
|
||||
struct AchievementEntry;
|
||||
struct AreaTrigger;
|
||||
struct AuctionEntry;
|
||||
struct CompletedAchievementData;
|
||||
struct Condition;
|
||||
struct ConditionSourceInfo;
|
||||
|
||||
@ -4544,6 +4544,11 @@ void Spell::finish(bool ok)
|
||||
// Xinef: Reset cooldown event in case of fail cast
|
||||
if (m_spellInfo->IsCooldownStartedOnEvent())
|
||||
m_caster->ToPlayer()->SendCooldownEvent(m_spellInfo, 0, 0, false);
|
||||
|
||||
// Rogue fix: Remove Cold Blood if Mutilate off-hand failed
|
||||
if (m_spellInfo->Id == 27576) // Mutilate, off-hand
|
||||
if (m_caster->HasAura(14177))
|
||||
m_caster->RemoveAura(14177);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5037,7 +5037,7 @@ void Spell::EffectLeapBack(SpellEffIndex effIndex)
|
||||
float speedxy = m_spellInfo->Effects[effIndex].MiscValue / 10.0f;
|
||||
float speedz = damage / 10.0f;
|
||||
//1891: Disengage
|
||||
m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellFamilyName != SPELLFAMILY_HUNTER);
|
||||
unitTarget->JumpTo(speedxy, speedz, m_spellInfo->SpellFamilyName != SPELLFAMILY_HUNTER);
|
||||
|
||||
if (m_caster->IsPlayer())
|
||||
{
|
||||
|
||||
@ -271,10 +271,15 @@ public:
|
||||
///- %Parse the command line arguments
|
||||
char* accountName = strtok((char*)args, " ");
|
||||
char* password = strtok(nullptr, " ");
|
||||
char* email = strtok(nullptr, " ");
|
||||
|
||||
if (!accountName || !password)
|
||||
return false;
|
||||
|
||||
AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password));
|
||||
// if email is not specified, use empty string
|
||||
std::string emailStr = email ? email : "";
|
||||
|
||||
AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password), emailStr);
|
||||
switch (result)
|
||||
{
|
||||
case AOR_OK:
|
||||
|
||||
@ -38,13 +38,14 @@ public:
|
||||
{
|
||||
static ChatCommandTable gmCommandTable =
|
||||
{
|
||||
{ "chat", HandleGMChatCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "fly", HandleGMFlyCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "ingame", HandleGMListIngameCommand, SEC_PLAYER, Console::Yes },
|
||||
{ "list", HandleGMListFullCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "visible", HandleGMVisibleCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "on", HandleGMOnCommand, SEC_MODERATOR, Console::No },
|
||||
{ "off", HandleGMOffCommand, SEC_MODERATOR, Console::No }
|
||||
{ "chat", HandleGMChatCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "fly", HandleGMFlyCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "ingame", HandleGMListIngameCommand, SEC_PLAYER, Console::Yes },
|
||||
{ "list", HandleGMListFullCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "visible", HandleGMVisibleCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "on", HandleGMOnCommand, SEC_MODERATOR, Console::No },
|
||||
{ "off", HandleGMOffCommand, SEC_MODERATOR, Console::No },
|
||||
{ "spectator", HandleGMSpectatorCommand, SEC_GAMEMASTER, Console::No },
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
@ -236,6 +237,19 @@ public:
|
||||
handler->SendNotification(LANG_GM_OFF);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMSpectatorCommand(ChatHandler* handler, Optional<bool> enable)
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
|
||||
if (enable.has_value())
|
||||
player->SetGMSpectator(*enable);
|
||||
else
|
||||
player->SetGMSpectator(!player->IsGMSpectator());
|
||||
handler->SendNotification(player->IsGMSpectator() ? LANG_GM_SPECTATOR_ON : LANG_GM_SPECTATOR_OFF);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_gm_commandscript()
|
||||
|
||||
@ -86,16 +86,35 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant<Hyperlink<creature_entry>, uint32> cId)
|
||||
static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant<Hyperlink<creature_entry>, uint32> cId, Optional<uint32> _pos)
|
||||
{
|
||||
CreatureData const* spawnpoint = GetCreatureData(handler, *cId);
|
||||
uint32 pos = 1;
|
||||
if (_pos)
|
||||
{
|
||||
pos = *_pos;
|
||||
if (pos < 1)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!spawnpoint)
|
||||
std::vector<CreatureData const*> spawnpoints = GetCreatureDataList(*cId);
|
||||
|
||||
if (spawnpoints.empty())
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GOCREATNOTFOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spawnpoints.size() < pos)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureData const* spawnpoint = spawnpoints[--pos];
|
||||
|
||||
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
|
||||
}
|
||||
|
||||
@ -153,16 +172,35 @@ public:
|
||||
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
|
||||
}
|
||||
|
||||
static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId)
|
||||
static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId, Optional<uint32> _pos)
|
||||
{
|
||||
GameObjectData const* spawnpoint = GetGameObjectData(handler, goId);
|
||||
uint32 pos = 1;
|
||||
if (_pos)
|
||||
{
|
||||
pos = *_pos;
|
||||
if (pos < 1)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!spawnpoint)
|
||||
std::vector<GameObjectData const*> spawnpoints = GetGameObjectDataList(goId);
|
||||
|
||||
if (spawnpoints.empty())
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GOOBJNOTFOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spawnpoints.size() < pos)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObjectData const* spawnpoint = spawnpoints[--pos];
|
||||
|
||||
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
|
||||
}
|
||||
|
||||
@ -509,6 +547,22 @@ public:
|
||||
return spawnpoint;
|
||||
}
|
||||
|
||||
static std::vector<CreatureData const*> GetCreatureDataList(uint32 entry)
|
||||
{
|
||||
std::vector<CreatureData const*> spawnpoints;
|
||||
for (auto const& pair : sObjectMgr->GetAllCreatureData())
|
||||
{
|
||||
if (pair.second.id1 != entry)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
spawnpoints.emplace_back(&pair.second);
|
||||
}
|
||||
|
||||
return spawnpoints;
|
||||
}
|
||||
|
||||
static GameObjectData const* GetGameObjectData(ChatHandler* handler, uint32 entry)
|
||||
{
|
||||
GameObjectData const* spawnpoint = nullptr;
|
||||
@ -532,6 +586,22 @@ public:
|
||||
|
||||
return spawnpoint;
|
||||
}
|
||||
|
||||
static std::vector<GameObjectData const*> GetGameObjectDataList(uint32 entry)
|
||||
{
|
||||
std::vector<GameObjectData const*> spawnpoints;
|
||||
for (auto const& pair : sObjectMgr->GetAllGOData())
|
||||
{
|
||||
if (pair.second.id != entry)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
spawnpoints.emplace_back(&pair.second);
|
||||
}
|
||||
|
||||
return spawnpoints;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_go_commandscript()
|
||||
|
||||
@ -74,7 +74,7 @@ public:
|
||||
|
||||
if (sGuildMgr->GetGuildByName(guildName))
|
||||
{
|
||||
handler->SendErrorMessage(LANG_GUILD_RENAME_ALREADY_EXISTS);
|
||||
handler->SendErrorMessage(LANG_GUILD_RENAME_ALREADY_EXISTS, guildName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -249,6 +249,20 @@ public:
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_BANK_GOLD, guild->GetTotalBankMoney() / 100 / 100); // Bank Gold (in gold coins)
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_MOTD, guild->GetMOTD()); // Message of the Day
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_EXTRA_INFO, guild->GetInfo()); // Extra Information
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT rid, rname FROM guild_rank WHERE guildid = {}", guild->GetId());
|
||||
if (result)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_RANKS);
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 rid = fields[0].Get<uint32>();
|
||||
std::string rname = fields[1].Get<std::string>();
|
||||
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_RANKS_LIST, rid, rname);
|
||||
} while (result->NextRow());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -74,7 +74,7 @@ struct boss_servant_quarters : public BossAI
|
||||
context.Repeat(12s, 18s);
|
||||
}).Schedule(10s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true)))
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, 40.0f, false, true)))
|
||||
{
|
||||
me->CastSpell(target, SPELL_DIVE);
|
||||
}
|
||||
|
||||
@ -1200,23 +1200,6 @@ class spell_chapter5_light_of_dawn_aura : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_chapter5_rebuke : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_chapter5_rebuke);
|
||||
|
||||
void HandleLeapBack(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitEffect(effIndex);
|
||||
if (Unit* unitTarget = GetHitUnit())
|
||||
unitTarget->KnockbackFrom(2282.86f, -5263.45f, 40.0f, 8.0f);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunchTarget += SpellEffectFn(spell_chapter5_rebuke::HandleLeapBack, EFFECT_0, SPELL_EFFECT_LEAP_BACK);
|
||||
}
|
||||
};
|
||||
|
||||
// 58552 - Return to Orgrimmar
|
||||
// 58533 - Return to Stormwind
|
||||
enum ReturnToCapital
|
||||
@ -1317,6 +1300,5 @@ void AddSC_the_scarlet_enclave_c5()
|
||||
{
|
||||
new npc_highlord_darion_mograine();
|
||||
RegisterSpellScript(spell_chapter5_light_of_dawn_aura);
|
||||
RegisterSpellScript(spell_chapter5_rebuke);
|
||||
RegisterSpellScript(spell_chapter5_return_to_capital);
|
||||
}
|
||||
|
||||
@ -381,14 +381,8 @@ struct boss_kiljaeden : public BossAI
|
||||
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
|
||||
{
|
||||
anveena->RemoveAllAuras();
|
||||
anveena->DespawnOrUnsummon(3500);
|
||||
}
|
||||
}, 34s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
|
||||
{
|
||||
anveena->CastSpell(anveena, SPELL_SACRIFICE_OF_ANVEENA, true);
|
||||
anveena->DespawnOrUnsummon(1500);
|
||||
DoCastSelf(SPELL_CUSTOM_08_STATE, true);
|
||||
me->SetUnitFlag(UNIT_FLAG_PACIFIED);
|
||||
scheduler.CancelAll();
|
||||
|
||||
@ -213,7 +213,7 @@ struct npc_dark_fiend : public ScriptedAI
|
||||
Unit* target = nullptr;
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* muru = instance->GetCreature(DATA_MURU))
|
||||
target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, FarthestTargetSelector(me, 50.0f, true, true));
|
||||
target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, RangeSelector(me, 50.0f, true, true));
|
||||
|
||||
if (target)
|
||||
{
|
||||
|
||||
@ -530,11 +530,21 @@ class spell_dk_bone_shield : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_dk_bone_shield);
|
||||
|
||||
uint32 lastChargeUsedTime = 0;
|
||||
|
||||
void HandleProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
uint32 currentTime = getMSTime();
|
||||
// Checks for 2 seconds between uses of bone shield charges
|
||||
if ((currentTime - lastChargeUsedTime) < 2000)
|
||||
return;
|
||||
|
||||
if (!eventInfo.GetSpellInfo() || !eventInfo.GetSpellInfo()->IsTargetingArea())
|
||||
{
|
||||
DropCharge();
|
||||
lastChargeUsedTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@ -5431,6 +5431,22 @@ private:
|
||||
uint32 _spellId;
|
||||
};
|
||||
|
||||
class spell_gen_cooldown_all : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_cooldown_all);
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Player* player = GetHitPlayer())
|
||||
player->RemoveAllSpellCooldown();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gen_cooldown_all::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_generic_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_silithyst);
|
||||
@ -5593,4 +5609,5 @@ void AddSC_generic_spell_scripts()
|
||||
RegisterSpellScript(spell_gen_proc_on_victim);
|
||||
RegisterSpellScriptWithArgs(spell_gen_translocate, "spell_gen_translocate_down", SPELL_TRANSLOCATION_DOWN);
|
||||
RegisterSpellScriptWithArgs(spell_gen_translocate, "spell_gen_translocate_up", SPELL_TRANSLOCATION_UP);
|
||||
RegisterSpellScript(spell_gen_cooldown_all);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user