Distribution des bases : script de release, et les 2 tables du Siege

Le depot fournissait deja des schemas auth et characters vierges, mais pas les
bases de contenu : personne ne pouvait monter une copie conforme du royaume.
Elles ne peuvent pas vivre dans l historique git (dc_world pese 880 Mo, ~79 Mo
gzippe, et GitHub refuse au-dela de 100 Mo par fichier) : le canal correct est
l asset de Release, celui qu utilise deja l amont.

sylvania/scripts/db-release-github.sh dumpe dc_world et dc_hotfixes en clair,
calcule les empreintes et depose le tout en Release BROUILLON, a relire avant
publication. Deux precautions apres verification des dumps reels :

- MariaDB 11.4 ecrit ses tables en utf8mb4_uca1400_ai_ci, collation inconnue de
  MySQL 8 : un import s y arretait sur "Unknown collation". Le script la
  reecrit en utf8mb4_unicode_ci, reconnue des deux moteurs et de meme
  semantique, et refuse de produire un dump ou il en resterait.
- Les tables de travail bak_* et tmp_* laissees par d anciennes maintenances
  (7 tables) sont exclues : ce n est pas du contenu.

Test de restauration complet passe : 248 tables, updates a 332 lignes (le core
ne rejouera donc pas sql/updates/world), 110 483 creature_template et 29 013
quest_template, aucune erreur.

Par ailleurs capital_siege_state et capital_siege_history n existaient que dans
sql/sylvania/capital_siege.sql, hors du mecanisme de mise a jour : une
installation neuve avait un schema characters incomplet et le module ecrivait
dans des tables absentes. Le patch est repris tel quel en fichier d update.

Enfin, les prerequis annoncaient MySQL 8.0 alors que le serveur tourne sous
MariaDB 11.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
SylvaniaCore deploy
2026-08-25 22:28:22 +02:00
parent 6fac9ded3e
commit b182593051
3 changed files with 275 additions and 1 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ Au-delà du core amont, le royaume apporte ses propres systèmes :
- **CMake 3.31+**
- **Boost 1.84.0**
- **MySQL 8.0**
- **MySQL 8.0** ou **MariaDB 10.6+** (le royaume tourne sur MariaDB 11.4)
- **OpenSSL 3.x**
- **GCC / Clang / MSVC** (Visual Studio 2022 recommandé)
@@ -0,0 +1,85 @@
--
-- Siege des Capitales : les deux tables d etat vivent dans la base
-- characters, mais n existaient que dans sql/sylvania/capital_siege.sql,
-- hors du mecanisme de mise a jour automatique. Une installation neuve se
-- retrouvait donc avec un schema characters incomplet : le module ecrivait
-- dans des tables absentes.
--
-- Ce fichier reprend le patch a l identique. Il est idempotent
-- (CREATE TABLE IF NOT EXISTS + INSERT IGNORE) : sans effet sur une base ou
-- le patch a deja ete passe a la main.
--
--
-- SylvaniaCore - Module "Siege des Capitales"
-- Base : dc_characters (etat mutable ecrit par le worldserver, donc hors de la
-- base de contenu dc_world qui est reimportee a chaque mise a jour).
--
-- Deux tables :
-- capital_siege_state : ligne unique, l ordonnancement du module. Elle porte
-- le verrou anti-rejeu quotidien et l alternance de
-- faction, qui doivent survivre a un redemarrage.
-- capital_siege_history : une ligne par evenement, ouverte au declenchement et
-- refermee a la fin (ou au demarrage suivant du core
-- si le serveur s est arrete en plein siege).
--
-- Toutes les ecritures passent par des requetes preparees declarees dans
-- src/server/database/Database/Implementation/CharacterDatabase.{h,cpp}.
--
-- ---------------------------------------------------------------------------
-- Etat de l ordonnanceur (une seule ligne, id = 1)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `capital_siege_state` (
`id` TINYINT(3) UNSIGNED NOT NULL DEFAULT 1
COMMENT 'Toujours 1 : la table ne contient qu une ligne',
`last_event_day` INT(10) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Jour serveur (epoch local / 86400) du dernier evenement consomme. Verrou anti-rejeu quotidien',
`last_attacker_team` TINYINT(4) NOT NULL DEFAULT -1
COMMENT 'Derniere faction attaquante : 0 = Alliance, 1 = Horde, -1 = aucune. Sert a l alternance stricte',
`scheduled_day` INT(10) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Jour serveur du tirage courant',
`scheduled_time` INT(10) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Horodatage unix du declenchement tire pour scheduled_day',
`scheduled_team` TINYINT(4) NOT NULL DEFAULT -1
COMMENT 'Faction attaquante tiree pour scheduled_day : 0 = Alliance, 1 = Horde, -1 = aucune',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='Siege des Capitales : ordonnancement persistant';
-- ---------------------------------------------------------------------------
-- Historique des evenements
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `capital_siege_history` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`start_time` INT(10) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Horodatage unix du declenchement',
`end_time` INT(10) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Horodatage unix de la fin, 0 tant que l evenement est en cours',
`attacker_team` TINYINT(4) NOT NULL DEFAULT -1
COMMENT '0 = Alliance, 1 = Horde',
`target_map` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Carte de la capitale assaillie (0 = Hurlevent, 1 = Orgrimmar)',
`boss_entry` INT(10) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'creature_template du dirigeant vise',
`outcome` TINYINT(4) NOT NULL DEFAULT 0
COMMENT '0 = en cours, 1 = victoire, 2 = temps ecoule, 3 = annule GM, 4 = arret d urgence (charge), 5 = interrompu (arret du serveur)',
`duration` INT(10) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Duree effective en secondes',
`bots_spawned` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Nombre de bots effectivement deployes',
`bots_lost` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0
COMMENT 'Nombre de bots tues pendant l assaut',
`triggered_by` VARCHAR(32) NOT NULL DEFAULT 'auto'
COMMENT 'auto = ordonnanceur, sinon nom du GM declencheur',
PRIMARY KEY (`id`),
KEY `idx_outcome` (`outcome`),
KEY `idx_start_time` (`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='Siege des Capitales : historique des evenements';
-- Ligne d etat initiale. Aucune faction n a encore attaque : le premier
-- evenement sera donc mene par l Alliance.
INSERT IGNORE INTO `capital_siege_state`
(`id`, `last_event_day`, `last_attacker_team`, `scheduled_day`, `scheduled_time`, `scheduled_team`)
VALUES (1, 0, -1, 0, 0, -1);
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env bash
#
# Publie les bases de contenu du royaume (dc_world + dc_hotfixes) comme assets
# d une Release GitHub sur BlaMacfly/SylvaniaCore.
#
# Pourquoi une Release et pas le depot : dc_world pese ~880 Mo en base (~78 Mo
# une fois dumpe et gzippe) et dc_hotfixes ~126 Mo. Git ne sait pas differencier
# une archive gzip : chaque rafraichissement alourdirait l historique de ~80 Mo
# a jamais, et GitHub refuse tout fichier de plus de 100 Mo. Les assets de
# Release, eux, vivent hors de l historique et montent a 2 Go piece.
#
# Contrairement a ~/scripts/db-backup-world.sh (sauvegarde chiffree, depot
# prive), ce script produit des dumps EN CLAIR destines a etre publics. Il ne
# touche jamais a dc_characters ni a dc_auth : ces bases contiennent des donnees
# de comptes et de personnages, et leurs schemas vierges sont deja fournis dans
# sql/base/ du depot.
#
# Prerequis : un jeton GitHub a portee fine (Contents: Read and write sur le
# seul depot SylvaniaCore) depose dans ~/.config/sylvania-github-token, en 600.
#
# Usage :
# db-release-github.sh --dry-run # dumpe et verifie, ne publie rien
# db-release-github.sh # dumpe et publie la Release
# db-release-github.sh --tag DB-SYLVANIA-20260901
#
set -euo pipefail
REPO_SLUG="${SYLVANIA_REPO_SLUG:-BlaMacfly/SylvaniaCore}"
TOKEN_FILE="${SYLVANIA_GH_TOKEN_FILE:-$HOME/.config/sylvania-github-token}"
WORKDIR="${SYLVANIA_RELEASE_WORKDIR:-$HOME/db-release}"
MIN_FREE_MB=2048
DATE="$(date '+%Y%m%d')"
TAG="DB-SYLVANIA-${DATE}"
DRY_RUN=0
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY_RUN=1; shift ;;
--tag) TAG="${2:?--tag attend une valeur}"; shift 2 ;;
-h|--help) sed -n '2,24p' "$0"; exit 0 ;;
*) echo "Option inconnue : $1" >&2; exit 2 ;;
esac
done
die() { echo "ERREUR: $*" >&2; exit 1; }
# --- Verifications preliminaires ---------------------------------------------
command -v mysqldump >/dev/null || die "mysqldump introuvable"
command -v curl >/dev/null || die "curl introuvable"
command -v gzip >/dev/null || die "gzip introuvable"
mkdir -p "$WORKDIR"
free_mb=$(df -Pm "$WORKDIR" | awk 'NR==2 {print $4}')
[ "$free_mb" -ge "$MIN_FREE_MB" ] || die "espace disque insuffisant sur $WORKDIR : ${free_mb} Mo libres, ${MIN_FREE_MB} Mo requis"
if [ "$DRY_RUN" -eq 0 ]; then
[ -s "$TOKEN_FILE" ] || die "jeton GitHub absent : $TOKEN_FILE (voir l en-tete de ce script)"
perms=$(stat -c '%a' "$TOKEN_FILE")
[ "$perms" = "600" ] || die "$TOKEN_FILE doit etre en 600 (actuellement $perms)"
fi
# --- Dumps --------------------------------------------------------------------
# Flags alignes sur ~/scripts/db-backup-world.sh, deja eprouves sur le serveur
# en production. Les tables `updates` et `updates_include` sont volontairement
# conservees : elles portent l historique deja applique, ce qui evite au core de
# rejouer les ~330 fichiers de sql/updates/world sur une base qui les contient
# deja.
declare -A DUMPS=( [world]=dc_world [hotfixes]=dc_hotfixes )
ASSETS=()
for name in world hotfixes; do
src="${DUMPS[$name]}"
out="${WORKDIR}/sylvania_${name}_${DATE}.sql.gz"
echo "==> dump ${src} -> $(basename "$out")"
# Les tables de travail laissees par d anciennes maintenances (bak_*, tmp_*)
# ne sont pas du contenu : inutile de les publier.
ignore=()
while IFS= read -r t; do
[ -n "$t" ] && ignore+=( "--ignore-table=${src}.${t}" )
done < <(sudo mysql -N -B -e "select table_name from information_schema.tables \
where table_schema='${src}' \
and (table_name like 'bak\\_%' or table_name like 'tmp\\_%');" 2>/dev/null)
[ ${#ignore[@]} -gt 0 ] && echo " ${#ignore[@]} table(s) de travail exclue(s)"
# Portabilite MySQL : le serveur tourne sous MariaDB 11.4, dont la collation
# par defaut (utf8mb4_uca1400_*) n existe pas sous MySQL 8 -- un import s y
# arreterait sur "Unknown collation". utf8mb4_unicode_ci est reconnue par les
# deux moteurs et partage la meme semantique (UCA, insensible a la casse et
# aux accents).
if ! sudo mysqldump --single-transaction --quick --no-tablespaces \
${ignore[@]+"${ignore[@]}"} "$src" \
| sed -E 's/utf8mb4_uca1400_[a-z_]+/utf8mb4_unicode_ci/g' \
| gzip -c > "$out"; then
rm -f "$out"; die "le dump de ${src} a echoue"
fi
[ -s "$out" ] || die "dump vide pour ${src}"
# Un dump tronque (mysqldump interrompu) ne porte pas sa ligne de cloture.
if ! gzip -dc "$out" | tail -5 | grep -q "Dump completed"; then
rm -f "$out"; die "dump de ${src} tronque : ligne de cloture absente"
fi
if gzip -dc "$out" | grep -q "uca1400"; then
rm -f "$out"; die "collation MariaDB residuelle dans le dump de ${src}"
fi
ASSETS+=("$out")
echo " $(du -h "$out" | cut -f1)"
done
# --- Empreintes ---------------------------------------------------------------
SUMS="${WORKDIR}/SHA256SUMS-${DATE}.txt"
( cd "$WORKDIR" && sha256sum "$(basename "${ASSETS[0]}")" "$(basename "${ASSETS[1]}")" ) > "$SUMS"
ASSETS+=("$SUMS")
cat "$SUMS"
# --- Corps de la Release ------------------------------------------------------
BODY_FILE="${WORKDIR}/body-${DATE}.md"
cat > "$BODY_FILE" <<BODYEOF
Bases de contenu du royaume **La Legion de Sylvania**, en date du ${DATE}.
Ce sont les bases \`world\` et \`hotfixes\` telles qu elles tournent en production :
la base amont DestinyCore augmentee de tous les correctifs de contenu du royaume
(campagnes, donjons, butin, localisation frFR, modules Mercenaires et Siege des
Capitales). Elles remplacent la release DB amont si vous voulez une copie
conforme du royaume plutot qu une installation DestinyCore de base.
Les bases \`auth\` et \`characters\` ne sont pas publiees : elles contiennent des
comptes et des personnages. Leurs schemas vierges sont dans \`sql/base/\` du depot.
### Import
\`\`\`bash
gunzip -c sylvania_world_${DATE}.sql.gz | mysql -u trinity -p world
gunzip -c sylvania_hotfixes_${DATE}.sql.gz | mysql -u trinity -p hotfixes
\`\`\`
Ces dumps ne contiennent ni \`CREATE DATABASE\` ni \`USE\` : creez les bases
d abord (\`sql/create/create_mysql.sql\`) et choisissez librement leurs noms.
La table \`updates\` est incluse et deja renseignee : le worldserver n aura donc
pas a rejouer les fichiers de \`sql/updates/world\`. Laissez malgre tout
\`Updates.EnableDatabases = 31\` et \`Updates.AutoSetup = 1\` pour que les
mises a jour ulterieures s appliquent seules.
Verifiez les archives avec \`sha256sum -c SHA256SUMS-${DATE}.txt\`.
BODYEOF
if [ "$DRY_RUN" -eq 1 ]; then
echo
echo "--- MODE --dry-run : rien n a ete publie ---"
echo "Assets prets dans ${WORKDIR} :"
printf ' %s\n' "${ASSETS[@]}"
echo "Tag qui serait cree : ${TAG}"
exit 0
fi
# --- Publication --------------------------------------------------------------
TOKEN="$(cat "$TOKEN_FILE")"
API="https://api.github.com/repos/${REPO_SLUG}"
UPLOAD="https://uploads.github.com/repos/${REPO_SLUG}"
auth=(-H "Authorization: Bearer ${TOKEN}" -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28")
existing=$(curl -sf "${auth[@]}" "${API}/releases/tags/${TAG}" | sed -n 's/.*"id": \([0-9]*\).*/\1/p' | head -1 || true)
[ -n "$existing" ] && die "la release ${TAG} existe deja (id ${existing}) : supprimez-la ou passez --tag"
echo "==> creation de la release ${TAG}"
payload=$(python3 - "$TAG" "$BODY_FILE" <<'PYEOF'
import json, sys, io
tag = sys.argv[1]
body = io.open(sys.argv[2], encoding="utf-8").read()
print(json.dumps({"tag_name": tag, "name": "Bases Sylvania " + tag.split("-")[-1],
"body": body, "draft": True, "prerelease": False}))
PYEOF
)
release_id=$(curl -sf "${auth[@]}" -X POST "${API}/releases" -d "$payload" \
| sed -n 's/.*"id": \([0-9]*\).*/\1/p' | head -1)
[ -n "$release_id" ] || die "creation de la release impossible"
for a in "${ASSETS[@]}"; do
echo "==> envoi de $(basename "$a")"
curl -sf "${auth[@]}" -H "Content-Type: application/octet-stream" \
--data-binary @"$a" \
"${UPLOAD}/releases/${release_id}/assets?name=$(basename "$a")" >/dev/null \
|| die "envoi de $(basename "$a") echoue"
done
echo
echo "Release ${TAG} creee en BROUILLON : https://github.com/${REPO_SLUG}/releases"
echo "Relisez-la puis publiez-la depuis l interface GitHub."