Compare commits

...

10 Commits

Author SHA1 Message Date
sindoring d7701b5b98 production setup 2026-08-31 21:32:14 +04:00
SylvaniaCore deploy e1ccf30afc Sessions : les comptes au-dessus du niveau 0 ne sont plus coupes pour inactivite
Demande : « j aimerai que les comptes au-dessus du numero 0, c est a dire
les comptes GM/testeur/admin, ne soient pas soumis en jeu a la
deconnexion automatique en cas d absence prolongee ».

La coupure vient de WorldSession::Update :

    if (!IsBotSession() && IsConnectionIdle())
        m_Socket[CONNECTION_TYPE_REALM]->CloseSocket();

IsConnectionIdle() s appuie sur m_timeOutTime, initialise depuis
SocketTimeOutTime (900 000 ms, soit 15 minutes) et decremente a chaque
tick sans paquet entrant.

On ajoute GetSecurity() <= SEC_PLAYER a la condition. Les comptes de
niveau superieur restent connectes indefiniment ; les joueurs ordinaires
demeurent soumis au delai, la protection contre les sessions fantomes
gardant tout son interet pour eux.

Motif concret : ces comptes restent volontairement inactifs de longues
minutes pour observer une zone, suivre un evenement scripte ou attendre
le resultat d un test -- et se faisaient couper en plein travail, parfois
au milieu d une instance.

Portee actuelle : 5 comptes concernes (3 de niveau 1, 2 de niveau 4).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 10:32:05 +02:00
SylvaniaCore deploy 80a4a589f6 worldserver.conf.dist : pbotqa et les deux cles du Bond heroique manquaient 2026-08-31 10:29:26 +02:00
SylvaniaCore deploy 0bc9b016d6 Commandes : .npc near faisait tomber le serveur
Signale en jeu : « la commande .npc near fait planter le serveur ».
L hypothese de l utilisateur etait proche : ce n est pas le rayon en soi,
c est l absence de plafond.

La requete preparee WORLD_SEL_CREATURE_NEAREST n a AUCUNE limite :

  SELECT ... FROM creature
   WHERE map = ? AND (POW(x-?,2)+POW(y-?,2)+POW(z-?,2)) <= ?
   ORDER BY order_

Elle calcule trois puissances sur les 384 000 lignes de la table, sans
index utilisable, puis la boucle d affichage envoie UN message de
discussion PAR RESULTAT. Avec un rayon large cela represente des dizaines
de milliers de paquets pour une seule commande, ce qui sature la session.

La requete etant partagee avec d autres commandes, on pose les garde-fous
cote appelant : rayon plafonne a 500, affichage plafonne a 150 lignes.

Les omissions sont ANNONCEES et non silencieuses : la commande indique
combien de resultats n ont pas ete montres et invite a reduire le rayon.
Un plafond muet ferait croire a une recherche complete.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 10:26:10 +02:00
SylvaniaCore deploy 3a4c6c01dd Hyjal : parler a Jaina faisait tomber le serveur -- et faction 16 au Rivage brise
1) PLANTAGE DU SERVEUR, cause reelle de la coupure de cette nuit

Trace du vidage 3007513 :
  #0 Trinity::Assert(...)
  #1 npc_jaina_proudmoore::OnGossipHello(Player*, Creature*)
  #2 WorldSession::HandleGossipHelloOpcode

hyjal.cpp utilisait ENSURE_AI(hyjalAI, creature->AI()), qui ASSERTE. Or
GetAI() ne fabrique une hyjalAI que si GetHyjalAI() la trouve, donc
uniquement dans l instance du Mont Hyjal. Ailleurs la creature recoit une
IA quelconque et l assertion tue le process.

Declencheur : un exemplaire de Jaina (17772) se trouve sur la carte 0, a
Hurlevent (-8295, 1386), en plus de celui du Mont Hyjal. Lui parler
suffisait a planter le serveur -- faille exploitable par n importe quel
joueur, sans commande ni privilege.

Les 5 occurrences passent en dynamic_cast avec sortie propre.

J avais d abord conclu a une recursion en me fiant a la taille du vidage
(387 Mo contre 133). C ETAIT FAUX : cette taille reflete la memoire
allouee au moment du plantage, pas un debordement de pile. La trace, elle,
etait parfaitement lisible.

2) RIVAGE BRISE : factions demoniaques ramenees a 16

Etabli par TEST A/B, pas par raisonnement. Une seule entree basculee en
faction 16 (Molosse de l effroi gangrene, 90686), toutes choses egales
par ailleurs. Verdict en jeu : « les molosses sont maintenant
attaquables », les autres non.

La sonde SPAWNDBG confirme que seule la faction distingue les deux :
  Felstalker Dreadhound  faction=16    drapeaux=32768 drapeaux2=0  OK
  Felguard Legionnaire   faction=2780  drapeaux=32768 drapeaux2=0  bloque

Pourquoi 2780 echoue reste INEXPLIQUE : FactionTemplate.db2 lui donne
EnemyGroup=15 (ennemi de tous) et sa faction 1786 a ReputationIndex=-1,
donc aucune reputation n intervient. Sur le papier elle devrait etre
hostile. Le refus vient du client, qu aucune sonde serveur ne peut
observer. On retient donc la faction 16, demontree fonctionnelle dans ce
scenario meme -- ecart assume avec la donnee de reference.

101 entrees, 464 spawns. Effet secondaire bienvenu : les demons cessent
de s entretuer (Friend_0=14).

3) COMPTEUR : tout demon compte desormais

Signale : « les molosses sont attaquables mais ne comptent pas dans l
objectif ». OnUnitDeath ne reconnaissait que les cinq entrees invoquees
par le script. On s appuie desormais sur le type demon plutot que sur une
liste de 101 entrees qui vieillirait mal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 10:20:45 +02:00
SylvaniaCore deploy b0b876b76b README : renvoyer vers le wiki, section Documentation et allegement du depannage 2026-08-31 10:19:44 +02:00
SylvaniaCore deploy fa7a543b94 worldserver.conf.dist : les 10 cles du module Mercenaires manquaient 2026-08-31 10:09:14 +02:00
SylvaniaCore deploy 5408eae697 Rivage brise 1460 : UNIT_FLAG2_UNK5 rendait les demons inattaquables
Signale en jeu, nommement : Gangreseigneur Rakkan, Legionnaire
gangregarde, Molosse de l effroi gangrene. Et l observation decisive :
« les demons inattaquables se battent avec les demons attaquables ».

LA CAUSE EST DE MON FAIT. La transposition des modeles a importe
unit_flags2 sur 147 entrees. Ces creatures valaient 0 avant ; elles ont
recu 2097152, soit 0x200000 -- UNIT_FLAG2_UNK5.

CE DRAPEAU EST PARTICULIER : notre serveur l IGNORE totalement, aucune
de ses verifications ne le consulte. Le client, lui, l interprete et
refuse de designer la creature comme cible.

C est ce qui explique le symptome le plus deroutant de la serie : la
sonde posee dans _IsValidAttackTarget n a JAMAIS produit la moindre
ligne pour ces creatures. Le client refusait de lui-meme, sans jamais
interroger le serveur. L ABSENCE DE TRACE ETAIT L INFORMATION -- j ai
mis trois tours a la lire comme telle.

CORRELATION QUI TRANCHE :
  demons INVOQUES (attaquables) : unit_flags2 = 0
  demons STATIQUES (bloques)    : bit 0x200000 present
  67 entrees, 420 spawns.

Seul ce bit est retire, le reste de la colonne est preserve. Le serveur
ne s en sert pas : le retrait ne peut rien casser cote logique.

Egalement dans ce lot, deux sondes conservees le temps de la validation :
ATTDBG (recentree sur les factions 2780/1768) et SPAWNDBG (etat reel des
creatures a leur creation). Deux divergences d API relevees au passage :
getFaction() et getLevel(), en minuscule dans ce fork.

Retour arriere joint.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 22:51:16 +02:00
SylvaniaCore deploy 995122dc78 Rivage brise 1460 : les demons statiques etaient immunises aux joueurs
Signale en jeu : « les demons invoques c est ok mais pas les autres au
fond ». Les creatures invoquees par le script etaient frappables, les
placements statiques non.

LA CAUSE EST DE MON FAIT. La transposition des modeles d hier a importe
unit_flags sur 136 entrees. Parmi les valeurs reprises, 33536 et
537166592 contiennent le bit 256 -- UNIT_FLAG_IMMUNE_TO_PC. Dans le
coeur de reference un script retire vraisemblablement ce drapeau au bon
moment ; le notre ne gere aucun drapeau, les demons restaient donc
immunises en permanence.

Cela explique aussi pourquoi la sonde ATTDBG ne produisait plus rien : le
client refusait de lui-meme, sans jamais interroger le serveur. L absence
de trace etait l information.

PORTEE : uniquement les factions HOSTILES -- 2780 (30 entrees), 1768
(20 : Anetheron, Balnazzar, Brutallus...), 2878 (Krosus), 14 (Gul dan),
2877 (Lave gangrenee). Soit 53 entrees.

EPARGNES car l immunite y est legitime : factions 35, 2876, 2879, 1819 --
allies, pretres, montures, vaisseaux. 13 entrees conservees.

SIMPLIFICATION ASSUMEE : Krosus et Gul dan perdent aussi leur immunite,
alors qu une implementation fidele la retirerait au debut de leur etape.
Notre script ne gere aucun drapeau : la conserver rendrait les etapes 7
et 8 infranchissables. La progression reste pilotee par la machine a
etats du script.

Retour arriere joint.

A NOTER, non traite : les modeles de Varian (90713) et Jaina (90714)
sont ceux d anciennes versions. Le dump de reference ne stocke aucun
modele dans creature_template -- ses affichages viennent d ailleurs. Une
autre source sera necessaire. Cosmetique, non bloquant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 22:22:13 +02:00
SylvaniaCore deploy 0ac509e421 Rivage brise 1460 : le phasage rendait les creatures inattaquables
Signale en jeu : creatures visibles, hostiles, mais impossibles a cibler
-- alors qu elles pouvaient attaquer le joueur.

J avais enchaine trois hypotheses (phase, factions, modeles souches).
Les trois etaient de VRAIS defauts et meritaient correction, mais aucune
n etait la cause. J aurais du poser la sonde d abord.

VERDICT DE LA SONDE, dans _IsValidAttackTarget :
    Felblade Destroyer | vivante=1 | aucun drapeau bloquant
    reaction=1 (hostile) | mesPhases=0  sesPhases=1

Le joueur n a AUCUNE phase, la creature en a une. PhaseShift::CanSee
exige une intersection des phases, et UpdateUnphasedFlag retire le
statut « non phase » des qu un objet en possede une. Aucune intersection
possible.

C est MA modification precedente qui a introduit ce decalage : j avais
place les 757 spawns en phase 169 en croyant que le joueur y etait,
en me fiant a un commentaire du script. Il ne l etait pas.

CORRECTIF : suppression du phasage des deux cotes, ce qui rejoint la
configuration de la reference -- le dump laisse les 757 placements de
cette carte SANS phase. La phase 169 n existe d ailleurs pas dans
Phase.db2 du build 7.3.5.26972.
  - PhaseId remis a 0 sur les 757 creatures et les 101 objets ;
  - AddPhase retire de OnPlayerEnter ;
  - FinalizeSummon ne phase plus rien (conservee comme point de passage
    unique, sans quoi les invocations deviendraient invisibles a un
    joueur non phase -- le meme probleme en sens inverse).

La sonde ATTDBG est CONSERVEE le temps de la validation en jeu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 22:11:21 +02:00
32 changed files with 39423 additions and 21 deletions
+8
View File
@@ -0,0 +1,8 @@
.git
.github
build
data
docker/db-dumps
*.log
*.pid
+10
View File
@@ -0,0 +1,10 @@
DB_ROOT_PASSWORD=change-me
DB_USER=sylvania
DB_PASSWORD=sylvania
EXTERNAL_ADDRESS=127.0.0.1
REALM_NAME=Sylvania Solo
REALM_ADDRESS=127.0.0.1
REALM_PORT=8086
BUILD_JOBS=2
BUILD_TYPE=Release
IMAGE_TAG=local
+13
View File
@@ -0,0 +1,13 @@
# Copy to .env.production and replace both passwords before deployment.
DB_ROOT_PASSWORD=GENERATE_A_LONG_RANDOM_ROOT_PASSWORD
DB_USER=sylvania
DB_PASSWORD=GENERATE_A_DIFFERENT_LONG_RANDOM_DB_PASSWORD
REALM_NAME=FelWell
REALM_ADDRESS=legion.moon-well.online
REALM_PORT=8085
EXTERNAL_ADDRESS=legion.moon-well.online
BUILD_JOBS=8
BUILD_TYPE=Release
IMAGE_TAG=production
+6
View File
@@ -9,6 +9,12 @@ build*/
*.kdev* *.kdev*
.DS_Store .DS_Store
CMakeLists.txt.user CMakeLists.txt.user
.env
.env.production
/data/
/docker/db-dumps/*.rar
/docker/db-dumps/*.sql
/docker/db-dumps/*.sql.gz
*.bak *.bak
*.patch *.patch
*.diff *.diff
+83
View File
@@ -0,0 +1,83 @@
# syntax=docker/dockerfile:1.7
FROM ubuntu:24.04 AS builder
ARG BUILD_TYPE=Release
ARG BUILD_JOBS=2
ENV DEBIAN_FRONTEND=noninteractive
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
cmake \
git \
libboost-filesystem-dev \
libboost-iostreams-dev \
libboost-locale-dev \
libboost-program-options-dev \
libboost-regex-dev \
libboost-system-dev \
libboost-thread-dev \
libbz2-dev \
libcurl4-openssl-dev \
libmariadb-dev \
libmariadb-dev-compat \
libncurses-dev \
libreadline-dev \
libssl-dev \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY . .
RUN cmake -S . -B /build \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-DCMAKE_INSTALL_PREFIX=/opt/sylvania \
-DTOOLS=OFF \
&& cmake --build /build --parallel "${BUILD_JOBS}" \
&& cmake --install /build
FROM ubuntu:24.04 AS runtime
ENV DEBIAN_FRONTEND=noninteractive
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
libboost-filesystem1.83.0 \
libboost-iostreams1.83.0 \
libboost-locale1.83.0 \
libboost-program-options1.83.0 \
libboost-regex1.83.0 \
libboost-system1.83.0 \
libboost-thread1.83.0 \
libbz2-1.0 \
libcurl4t64 \
libmariadb3 \
libncurses6 \
libreadline8t64 \
libssl3t64 \
mariadb-client \
zlib1g \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --system --uid 10001 --home /opt/sylvania --shell /usr/sbin/nologin sylvania
COPY --from=builder /opt/sylvania /opt/sylvania
COPY docker/entrypoint.sh /usr/local/bin/sylvania-entrypoint
RUN chmod +x /usr/local/bin/sylvania-entrypoint \
&& mkdir -p /opt/sylvania/data /opt/sylvania/logs \
&& chown -R sylvania:sylvania /opt/sylvania
USER sylvania
WORKDIR /opt/sylvania
EXPOSE 1119 8081 8085
ENTRYPOINT ["sylvania-entrypoint"]
CMD ["worldserver"]
+58
View File
@@ -0,0 +1,58 @@
# syntax=docker/dockerfile:1.7
FROM ubuntu:24.04 AS builder
ENV DEBIAN_FRONTEND=noninteractive
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
cmake \
git \
libboost-filesystem-dev \
libboost-iostreams-dev \
libboost-locale-dev \
libboost-program-options-dev \
libboost-regex-dev \
libboost-system-dev \
libboost-thread-dev \
libbz2-dev \
libcurl4-openssl-dev \
libmariadb-dev \
libmariadb-dev-compat \
libncurses-dev \
libreadline-dev \
libssl-dev \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY . .
RUN cmake -S . -B /build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/opt/sylvania \
-DSERVERS=OFF \
-DTOOLS=ON \
&& cmake --build /build --parallel 2 \
&& cmake --install /build
FROM ubuntu:24.04
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libboost-filesystem1.83.0 \
libboost-iostreams1.83.0 \
libboost-program-options1.83.0 \
libboost-regex1.83.0 \
libboost-system1.83.0 \
libbz2-1.0 \
libssl3t64 \
zlib1g \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /opt/sylvania/bin /opt/sylvania/bin
WORKDIR /client
+32 -10
View File
@@ -7,6 +7,7 @@
**Le core C++ du royaume [La Légion de Sylvania](https://legendesylvania.com)** **Le core C++ du royaume [La Légion de Sylvania](https://legendesylvania.com)**
Émulateur de serveur *World of Warcraft®* — Legion 7.3.5 Émulateur de serveur *World of Warcraft®* — Legion 7.3.5
[![Wiki](https://img.shields.io/badge/Wiki-documentation-0b7285?style=flat&logo=github)](https://github.com/BlaMacfly/SylvaniaCore/wiki)
[![Discord contributeurs](https://img.shields.io/badge/Discord-Espace%20contributeurs-5865F2?style=flat&logo=discord&logoColor=white)](https://discord.gg/qmQBXbuXkx) [![Discord contributeurs](https://img.shields.io/badge/Discord-Espace%20contributeurs-5865F2?style=flat&logo=discord&logoColor=white)](https://discord.gg/qmQBXbuXkx)
[![License: GPL v2](https://img.shields.io/badge/License-GPLv2-blue.svg)](./LICENSE) [![License: GPL v2](https://img.shields.io/badge/License-GPLv2-blue.svg)](./LICENSE)
[![Stars](https://img.shields.io/github/stars/BlaMacfly/SylvaniaCore.svg?style=flat&logo=github)](https://github.com/BlaMacfly/SylvaniaCore/stargazers) [![Stars](https://img.shields.io/github/stars/BlaMacfly/SylvaniaCore.svg?style=flat&logo=github)](https://github.com/BlaMacfly/SylvaniaCore/stargazers)
@@ -49,6 +50,23 @@ Au-delà du core amont, le royaume apporte ses propres systèmes :
--- ---
## 📚 Documentation
Ce README suffit pour **installer et lancer** un serveur. Tout le reste vit dans le
**[wiki du projet](https://github.com/BlaMacfly/SylvaniaCore/wiki)** :
| | |
| --- | --- |
| 🔧 **[Corriger le contenu](https://github.com/BlaMacfly/SylvaniaCore/wiki/Corriger-le-contenu)** | Les classes de bugs récurrentes de ce core — scripts C++ non rattachés, hooks morts, quêtes sans objectif, butin, phases résiduelles — et comment les trouver. **Le meilleur point d'entrée pour une première contribution.** |
| ⚙️ **[Configuration](https://github.com/BlaMacfly/SylvaniaCore/wiki/Configuration)** | Référence de toutes les clés de configuration propres au royaume |
| 🧩 **[Architecture du core](https://github.com/BlaMacfly/SylvaniaCore/wiki/Architecture-du-core)** | Arborescence, lignée amont, pièges d'architecture |
| 🤖 **Modules** | [PlayerBots](https://github.com/BlaMacfly/SylvaniaCore/wiki/Module-PlayerBots) · [Mercenaires](https://github.com/BlaMacfly/SylvaniaCore/wiki/Module-Mercenaires) · [Siège des Capitales](https://github.com/BlaMacfly/SylvaniaCore/wiki/Module-Siege-des-Capitales) · [Autres customs](https://github.com/BlaMacfly/SylvaniaCore/wiki/Autres-customs) |
| 💥 **[Diagnostic des crashs](https://github.com/BlaMacfly/SylvaniaCore/wiki/Diagnostic-des-crashs)** | Core dumps, redzone jemalloc, faux crashs d'arrêt |
| 🩺 **[FAQ Dépannage](https://github.com/BlaMacfly/SylvaniaCore/wiki/FAQ-Depannage)** | Écran de chargement, PNJ disparus, personnage bloqué, boss infaisable… |
| 🚧 **[Chantiers en cours](https://github.com/BlaMacfly/SylvaniaCore/wiki/Chantiers-en-cours)** | Ce qui est ouvert, ce qui est clos, et les **impasses connues** |
---
## 🛠️ Prérequis ## 🛠️ Prérequis
- **CMake 3.31+** - **CMake 3.31+**
@@ -59,6 +77,9 @@ Au-delà du core amont, le royaume apporte ses propres systèmes :
Plateformes supportées : **Linux, Windows, macOS**. Plateformes supportées : **Linux, Windows, macOS**.
> 📖 Paquets à installer, extraction des données client et compilation sur une machine modeste :
> **[Installation](https://github.com/BlaMacfly/SylvaniaCore/wiki/Installation)** sur le wiki.
--- ---
## 📦 Compilation ## 📦 Compilation
@@ -151,8 +172,8 @@ amont est livrée vide : c'est normal, tout l'historique est rejoué. Comptez pl
`sql/sylvania/` est la trace versionnée des correctifs data appliqués à la base du royaume `sql/sylvania/` est la trace versionnée des correctifs data appliqués à la base du royaume
(artefacts, campagnes, donjons, modules Mercenaires et Siège des Capitales…). Ils sont indépendants (artefacts, campagnes, donjons, modules Mercenaires et Siège des Capitales…). Ils sont indépendants
du mécanisme de mise à jour automatique et s'importent à la main, dans l'ordre chronologique, une du mécanisme de mise à jour automatique et s'importent à la main, dans l'ordre chronologique, une
fois les étapes précédentes terminées. La base `world` de production du royaume n'est pas fois les étapes précédentes terminées. **Chaque fichier annonce sa base cible dans son en-tête :
distribuée. le dossier n'en a pas une seule.** Détail et conventions : **[Bases de données](https://github.com/BlaMacfly/SylvaniaCore/wiki/Bases-de-donnees)**.
### 🩺 Bloqué sur l'écran de chargement ? ### 🩺 Bloqué sur l'écran de chargement ?
@@ -166,14 +187,12 @@ Received not handled opcode [CMSG_GET_ACCOUNT_CHARACTER_LIST ...]
`ResourceService` est un service Battle.net resté à l'état d'ébauche en amont, et `ResourceService` est un service Battle.net resté à l'état d'ébauche en amont, et
`CMSG_GET_ACCOUNT_CHARACTER_LIST` (liste des personnages inter-royaumes) est délibérément déclaré `CMSG_GET_ACCOUNT_CHARACTER_LIST` (liste des personnages inter-royaumes) est délibérément déclaré
`STATUS_UNHANDLED` dans `src/server/game/Server/Protocol/Opcodes.cpp`. Si le client reste bloqué au `STATUS_UNHANDLED` dans `src/server/game/Server/Protocol/Opcodes.cpp`.
chargement, cherchez plutôt du côté :
- d'une base `world` ou `hotfixes` mal importée — voir l'avertissement sur `sql/base/dev/` ; La cause est presque toujours une base `world` ou `hotfixes` mal importée — relisez l'avertissement
- du cache du client : videz son dossier `Cache` ; sur `sql/base/dev/` ci-dessus. Les autres pistes (cache client, données extraites, lecture de
- des données extraites — `dbc/`, `maps/`, `vmaps/`, `mmaps/`, `cameras/` et `gt/` doivent provenir `DBErrors.log`) sont détaillées dans la **[FAQ Dépannage](https://github.com/BlaMacfly/SylvaniaCore/wiki/FAQ-Depannage)**, avec les autres
d'un client **7.3.5 build 26972**, et `DataDir` doit pointer sur le dossier qui les contient ; symptômes fréquents.
- de `DBErrors.log` et des lignes de démarrage du worldserver, qui nomment la table fautive.
--- ---
@@ -191,7 +210,10 @@ ou nouvelle fonctionnalité :
1. Forkez le dépôt 1. Forkez le dépôt
2. Créez une branche dédiée 2. Créez une branche dédiée
3. Ouvrez une pull request 3. Ouvrez une pull request contre `sylvaniacore`
> 📖 Conventions du dépôt, style de commit, règles pour le SQL et doctrine de correction :
> **[Contribuer](https://github.com/BlaMacfly/SylvaniaCore/wiki/Contribuer)** sur le wiki.
Un Discord est ouvert **aux contributeurs et aux personnes qui souhaitent participer au Un Discord est ouvert **aux contributeurs et aux personnes qui souhaitent participer au
développement du core** : c'est l'endroit où discuter d'un correctif avant de se lancer, poser développement du core** : c'est l'endroit où discuter d'un correctif avant de se lancer, poser
+160
View File
@@ -0,0 +1,160 @@
# FelWell — Legion 7.3.5
Production-сборка SylvaniaCore для realm **FelWell**. Сервер рассчитан на
клиент World of Warcraft Legion **7.3.5 build 26972** и публикуется по адресу
`legion.moon-well.online`.
## Что входит в сборку
- SylvaniaCore: `worldserver` и `bnetserver`;
- MariaDB 11.4 с базами `auth`, `characters`, `world`, `hotfixes` и `shop`;
- Docker Compose для сборки и запуска всего стека;
- автоматическая настройка `auth.realmlist` из переменных окружения;
- русская локализация дополнительных `broadcast_text`;
- постоянные Docker volumes для базы данных и журналов.
## Требования к VPS
- Ubuntu 24.04;
- Docker Engine с Compose plugin;
- DNS-запись `legion.moon-well.online`, направленная на публичный IP VPS;
- открытые входящие TCP-порты `1119`, `8081` и `8085`;
- игровой порт MariaDB `3306` не должен быть открыт в Интернет.
В каталоге `data/` должны находиться данные, извлечённые из клиента
7.3.5.26972: `dbc`, `maps`, `vmaps`, `mmaps`, `cameras` и `gt`.
## Первый запуск
Создайте production-конфигурацию:
```bash
cp .env.production.example .env.production
nano .env.production
```
Обязательно замените `DB_ROOT_PASSWORD` и `DB_PASSWORD` на разные длинные
случайные пароли. Затем положите полные дампы `world` и `hotfixes` в
`docker/db-dumps/` и запустите сервер:
```bash
docker compose --env-file .env.production up --build -d
docker compose --env-file .env.production ps
docker compose --env-file .env.production logs -f bnetserver worldserver
```
При запуске запись realm автоматически получает следующие значения:
```text
name = FelWell
address = legion.moon-well.online
port = 8085
gamebuild = 26972
```
## Русские переводы
Дополнительные переводы находятся в `sql/translations/ruRU/`. Их можно
импортировать после инициализации базы:
```bash
set -a
. ./.env.production
set +a
for file in sql/translations/ruRU/broadcast_text_locale_ruRU_part_*.sql; do
docker compose --env-file .env.production exec -T database \
mariadb --binary-mode -uroot "-p${DB_ROOT_PASSWORD}" hotfixes < "$file"
done
docker compose --env-file .env.production restart worldserver
```
Импорт идемпотентный: существующие строки не перезаписываются.
## Свой Git-сервер и обновления GitHub
Используется стандартная схема с двумя remote:
- `origin` — ваш собственный Git-сервер, основное место хранения;
- `upstream` — публичный GitHub-репозиторий SylvaniaCore, только источник
обновлений.
GitHub уже настроен как `upstream`. Добавьте свой сервер, подставив настоящий
SSH URL:
```bash
git remote add origin git@YOUR_GIT_SERVER:YOUR_GROUP/SylvaniaCore.git
git push -u origin master
git remote -v
```
Рабочие изменения сначала коммитятся и отправляются только в ваш `origin`:
```bash
git add .
git commit -m "Configure FelWell production deployment"
git push origin master
```
Для получения очередных обновлений GitHub:
```bash
git status
git fetch upstream --prune
git switch master
git branch "backup/before-upstream-$(date +%F-%H%M)"
git merge upstream/sylvaniacore
```
Если возникли конфликты, разрешите их, сохраняя FelWell-настройки в
`compose.yaml`, `docker/`, `.env.production.example` и SQL-миграциях. После
сборки и проверки отправьте результат на собственный сервер:
```bash
docker compose --env-file .env.production build
docker compose --env-file .env.production up -d
docker compose --env-file .env.production logs --tail=200 worldserver bnetserver
git push origin master
```
Не выполняйте обновление при незакоммиченных изменениях. Файлы `.env`,
`.env.production`, игровые данные и полные дампы БД исключены из Git.
## Резервное копирование базы
Перед обновлением создайте дамп всех игровых баз:
```bash
set -a
. ./.env.production
set +a
docker compose --env-file .env.production exec -T database \
mariadb-dump -uroot "-p${DB_ROOT_PASSWORD}" \
--single-transaction --routines --events \
--databases auth characters world hotfixes shop \
| gzip > "felwell-$(date +%F-%H%M).sql.gz"
```
Храните резервные копии вне VPS. Docker volume защищает данные при пересоздании
контейнеров, но не заменяет внешнюю резервную копию.
## Полезные команды
```bash
# Состояние контейнеров
docker compose --env-file .env.production ps
# Последние журналы
docker compose --env-file .env.production logs --tail=200 worldserver bnetserver
# Перезапуск серверов без удаления БД
docker compose --env-file .env.production restart bnetserver worldserver
# Остановка стека с сохранением volumes
docker compose --env-file .env.production down
```
Не запускайте `docker compose down -v` на production: ключ `-v` удаляет volume
MariaDB вместе с игровыми аккаунтами и персонажами.
+309
View File
@@ -0,0 +1,309 @@
<div align="center">
<img src=".github/assets/sylvaniacore-logo.png" alt="SylvaniaCore" width="360">
# SylvaniaCore
**C++-ядро игрового мира [La Légion de Sylvania](https://legendesylvania.com)**<br>
Эмулятор сервера *World of Warcraft®* — Legion 7.3.5
[![Discord для разработчиков](https://img.shields.io/badge/Discord-Для%20разработчиков-5865F2?style=flat&logo=discord&logoColor=white)](https://discord.gg/qmQBXbuXkx)
[![Лицензия: GPL v2](https://img.shields.io/badge/Лицензия-GPLv2-blue.svg)](./LICENSE)
[![Звёзды](https://img.shields.io/github/stars/BlaMacfly/SylvaniaCore.svg?style=flat&logo=github)](https://github.com/BlaMacfly/SylvaniaCore/stargazers)
[![Форки](https://img.shields.io/github/forks/BlaMacfly/SylvaniaCore.svg?style=flat&logo=github)](https://github.com/BlaMacfly/SylvaniaCore/network/members)
[![Форк DestinyCore](https://img.shields.io/badge/форк-DestinyCore-2ea44f?logo=github)](https://github.com/slash-design/DestinyCore)
</div>
> Практическая инструкция по Docker, production-развёртыванию FelWell и
> синхронизации с собственным Git-сервером: [README.ru.md](./README.ru.md).
---
## 📖 О проекте
**SylvaniaCore** — ядро франкоязычного игрового мира **La Légion de Sylvania**
для *World of Warcraft® Legion 7.3.5*. Это форк
[DestinyCore](https://github.com/slash-design/DestinyCore), который, в свою
очередь, происходит из семейства TrinityCore. Проект постоянно развивается и
поддерживается для нужд игрового мира.
Репозиторий одновременно служит **актуальной кодовой базой** и **резервной
копией** production-сервера.
### Философия: «адаптивный blizzlike»
Это не *fun*-сервер и не сервер с *rates x∞*. Оригинальные значения Blizzard
(урон, баланс и экономика) **сохраняются**. Основная работа направлена на
**исправление отклонений от blizzlike**, а не на упрощение игры. Каждая
обнаруженная ошибка исправляется в источнике — в данных или в ядре, — а не
обходится командами игрового мастера.
---
## ✨ Дополнения SylvaniaCore
Помимо возможностей upstream-ядра, проект содержит собственные системы:
| Модуль | Описание |
| --- | --- |
| 🤖 **PlayerBots** | Управляемые боты-игроки (`src/server/game/PlayerBot`): групповые команды, роли танка и лекаря, управление экипировкой и автоматическое заполнение полей боя |
| ⚔️ **Осада столиц** | Ежедневные нападения отрядов ботов на столицы с назначенным командиром и PvP-флагом игроков (`src/server/game/CapitalSiege`) |
| 💰 **Наёмники** | Нанимаемые NPC-компаньоны: одиночный игрок может заключить с ними контракт за игровое золото (`src/server/game/Mercenary`) |
| 🇫🇷 **Локализация frFR** | Восстановление официальных французских текстов из клиента 7.3.5 — заданий, диалогов и broadcast-текстов — и перевод отсутствующего сценарного контента |
| 🐛 **Исправления контента** | Последовательное восстановление кампаний, подземелий и заданий по отдельным зонам: Мардум, Скитающийся остров, Вершина Смерча и другие |
---
## 🛠️ Требования
- **CMake 3.31+**
- **Boost 1.84.0**
- **MySQL 8.0** или **MariaDB 10.6+** — игровой мир использует MariaDB 11.4
- **OpenSSL 3.x**
- **GCC / Clang / MSVC** — рекомендуется Visual Studio 2022
Поддерживаемые платформы: **Linux, Windows и macOS**.
---
## 📦 Сборка
1. Клонируйте репозиторий:
```bash
git clone https://github.com/BlaMacfly/SylvaniaCore.git
cd SylvaniaCore
```
2. Настройте и соберите проект:
```bash
cmake -S . -B build -DTOOLS=ON
cmake --build build -j$(nproc)
```
3. Установите базы данных согласно разделу
[Установка базы данных](#-установка-базы-данных).
4. Запустите серверы:
```bash
./bin/worldserver
./bin/bnetserver
```
> ℹ️ В исходном коде намеренно сохранены внутренние имена upstream-проекта:
> `DestinyCore`, названия целей CMake и пути конфигурации. Это обеспечивает
> совместимость с upstream-обновлениями и существующими сценариями
> развёртывания.
### Docker Compose
Ядро, сервер Battle.net и MariaDB 11.4 можно собрать и запустить вместе:
```bash
cp .env.example .env
# Поместите DB_world_*.sql и DB_hotfixes_*.sql (или .sql.gz) в docker/db-dumps/
# Поместите dbc/, maps/, vmaps/, mmaps/, cameras/ и gt/ клиента 7.3.5 в data/
docker compose up --build -d
docker compose logs -f worldserver
```
Схемы `auth`, `characters` и `shop` импортируются автоматически при первом
запуске MariaDB. Полные дампы `world` и `hotfixes` также импортируются из
`docker/db-dumps/`. Перед публикацией сервера обязательно замените пароли в
`.env`. Объявляемый клиентам адрес задаётся переменной `EXTERNAL_ADDRESS`.
### Production-развёртывание FelWell
Production-шаблон настраивает игровой мир `FelWell` по адресу
`legion.moon-well.online:8085`:
```bash
cp .env.production.example .env.production
# Обязательно замените оба пароля в .env.production
docker compose --env-file .env.production up --build -d
docker compose --env-file .env.production logs -f bnetserver worldserver
```
При запуске запись `auth.realmlist` автоматически синхронизируется с
`REALM_NAME`, `REALM_ADDRESS` и `REALM_PORT`. DNS-запись `A/AAAA` должна
указывать на VPS, а брандмауэр должен разрешать TCP-порты `1119`, `8081` и
`8085`. MariaDB должна оставаться только во внутренней сети Docker и не должна
публиковаться в Интернет.
Volumes `database-data` и `sylvania-logs` сохраняют базу данных и журналы
соответственно. Изменения в `docker/db-dumps/` не импортируются повторно, если
база уже была инициализирована.
---
## 💾 Установка базы данных
Репозиторий содержит **только схемы** `auth`, `characters` и `shop`. Базы
`world` и `hotfixes` слишком велики для хранения в Git; их необходимо загрузить
из **релизов upstream-репозитория DestinyCore**.
> ⚠️ **Никогда не импортируйте файлы из `sql/base/dev/`.** Это **пустые**
> структуры таблиц без игровых данных, предназначенные для разработчиков
> upstream-проекта. После такого импорта `worldserver` может запуститься, но
> клиент останется на экране загрузки из-за пустой базы `world`.
### 1. Загрузка upstream-базы
Загрузите последний релиз базы на странице
[slash-design/DestinyCore/releases](https://github.com/slash-design/DestinyCore/releases).
На момент написания это `DB735.02.rar` размером около 84 МБ. Архив содержит два
дампа:
| Файл | База | Размер после распаковки |
| --- | --- | --- |
| `DB_world_735.02.sql` | `world` | около 375 МБ |
| `DB_hotfixes_735.02.sql` | `hotfixes` | около 127 МБ |
Оба дампа самостоятельно выполняют `CREATE DATABASE`, а затем `USE` для баз
`world` и `hotfixes`. Если нужны другие имена баз, измените эти две строки в
начале соответствующего файла.
### 2. Создание и импорт баз
```bash
# Базы auth / characters / world / hotfixes
mysql -u root -p < sql/create/create_mysql.sql
# База shop не создаётся upstream-скриптом
mysql -u root -p -e "CREATE DATABASE shop DEFAULT CHARACTER SET utf8;"
# Схемы из репозитория
mysql -u trinity -p auth < sql/base/auth_database.sql
mysql -u trinity -p characters < sql/base/characters_database.sql
mysql -u trinity -p shop < sql/base/shop_database.sql
# Полные базы из upstream-релиза
mysql -u trinity -p < DB_world_735.02.sql
mysql -u trinity -p < DB_hotfixes_735.02.sql
```
### 3. Автоматическое применение обновлений ядром
Не импортируйте файлы из `sql/updates/` вручную. В `worldserver.conf` должно
быть указано:
```ini
Updates.EnableDatabases = 31 # auth + characters + world + hotfixes + shop
Updates.AutoSetup = 1
```
При первом запуске `worldserver` самостоятельно применит около 330 файлов из
`sql/updates/world`, а также обновления для `characters` и `hotfixes`. Таблица
`updates` в upstream-дампах изначально пуста — это нормально: история
обновлений будет применена целиком. Процесс может занять несколько минут.
### 4. Исправления контента игрового мира (необязательно)
В `sql/sylvania/` хранится версионируемая история исправлений игровых данных:
артефактов, кампаний, подземелий, модулей «Наёмники» и «Осада столиц». Они не
относятся к механизму автоматических обновлений и импортируются вручную в
хронологическом порядке после завершения предыдущих этапов. Production-база
`world` игрового мира не распространяется.
### 🩺 Клиент завис на экране загрузки?
Следующие два сообщения появляются при каждом подключении на **всех** серверах
этого семейства и **не являются ошибками**:
```text
Client tried to call not implemented method ResourceService.GetContentHandle
Received not handled opcode [CMSG_GET_ACCOUNT_CHARACTER_LIST ...]
```
`ResourceService` — незавершённая upstream-реализация сервиса Battle.net, а
`CMSG_GET_ACCOUNT_CHARACTER_LIST`, то есть межсерверный список персонажей,
намеренно объявлен как `STATUS_UNHANDLED` в
`src/server/game/Server/Protocol/Opcodes.cpp`. Если клиент не проходит экран
загрузки, проверьте:
- правильность импорта `world` и `hotfixes`, учитывая предупреждение о
`sql/base/dev/`;
- кеш клиента — очистите каталог `Cache`;
- извлечённые данные: `dbc/`, `maps/`, `vmaps/`, `mmaps/`, `cameras/` и `gt/`
должны происходить из клиента **7.3.5 build 26972**, а `DataDir` должен
указывать на содержащий их каталог;
- `DBErrors.log` и начальные строки журнала `worldserver`, где будет указана
проблемная таблица.
---
## 🌍 Подключение к игровому миру
Игровой сервер открыт, а инструкции по подключению опубликованы на официальном
сайте: **[legendesylvania.com](https://legendesylvania.com)**.
---
## 🤝 Участие в разработке
Мы приветствуем исправления ошибок, улучшения документации и новые возможности:
1. Создайте форк репозитория.
2. Создайте отдельную ветку для изменения.
3. Откройте pull request.
Discord открыт **для разработчиков и всех желающих участвовать в развитии
ядра**. Там можно обсудить исправление до начала работы, задать вопросы по
архитектуре или попросить проверить pull request. Это не Discord игрового мира.
<a href="https://discord.gg/qmQBXbuXkx"><img src="https://img.shields.io/badge/Discord-Для%20разработчиков-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Присоединиться к Discord разработчиков"></a>
---
## 🐛 Сообщение об ошибке
Создайте обращение в [трекере задач](https://github.com/BlaMacfly/SylvaniaCore/issues).
Перед этим убедитесь, что аналогичная проблема ещё не зарегистрирована.
---
## 🙏 Благодарности
SylvaniaCore не существовал бы без проектов, на основе которых он создан:
- [DestinyCore](https://github.com/slash-design/DestinyCore) — upstream-ядро,
форком которого является этот репозиторий;
- [TrinityCore](https://github.com/TrinityCore/TrinityCore) — исходное семейство
проекта;
- [**ArgusCore**](https://github.com/Trion-Control-Panel/ArgusCore), проект
[FlyingPhoenix](https://github.com/fIyingPhoenix), — один из важнейших
ориентиров для SylvaniaCore. В нём проделана огромная работа над движком,
сетевым уровнем и механиками классов версии 7.3.5. Мы регулярно используем
его как источник решений при восстановлении крупных частей ядра. Спасибо за
открыто опубликованные наработки;
- [mod-playerbots](https://github.com/liyunfan1223/mod-playerbots) — источник
решений для логики ботов-игроков.
Состояние CI upstream-репозитория:
[![Windows x64](https://github.com/slash-design/DestinyCore/actions/workflows/win-x64-build.yml/badge.svg)](https://github.com/slash-design/DestinyCore/actions/workflows/win-x64-build.yml)
[![GCC](https://github.com/slash-design/DestinyCore/actions/workflows/gcc-build.yml/badge.svg)](https://github.com/slash-design/DestinyCore/actions/workflows/gcc-build.yml)
[![Clang](https://github.com/slash-design/DestinyCore/actions/workflows/clang-build.yml/badge.svg)](https://github.com/slash-design/DestinyCore/actions/workflows/clang-build.yml)
---
## 📜 Лицензия
Проект распространяется по лицензии **GPL v2.0**. См. файл
[LICENSE](./LICENSE).
*World of Warcraft® и Blizzard Entertainment® являются зарегистрированными
товарными знаками Blizzard Entertainment, Inc. Проект не связан с Blizzard
Entertainment и не одобрен этой компанией.*
---
<div align="center">
<img src=".github/assets/sylvaniacore-logo.png" alt="SylvaniaCore" width="90">
⭐ Если вам нравится SylvaniaCore, поставьте проекту звезду!
</div>
@@ -0,0 +1,100 @@
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102702;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=97510;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113054;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113055;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=110617;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102706;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113058;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=90506;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=94191;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113056;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=110616;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113057;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102696;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113053;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=94190;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=91967;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=94189;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=91970;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=101667;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102701;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113059;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=90525;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105176;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105169;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105168;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105171;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105170;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111079;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=90688;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111154;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111089;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=91902;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105166;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105163;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=111165;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111153;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111152;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111149;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111148;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=92558;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105192;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105188;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105190;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105185;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105187;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105186;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105181;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105180;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105182;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105179;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=90677;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105203;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=90515;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=90516;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111167;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111156;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111088;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111087;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105197;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105189;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111173;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111175;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111174;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105183;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105175;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105174;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105165;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105164;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111157;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111155;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111085;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111171;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105206;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105196;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=105167;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105205;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105200;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105199;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=111074;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=105172;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102698;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=92564;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=100621;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=110615;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=110614;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102704;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102703;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=102705;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=109591;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113037;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113036;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=109604;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=109592;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=113038;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=91588;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=109587;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=109586;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=93719;
UPDATE `creature_template` SET `faction`=2780 WHERE `entry`=90705;
UPDATE `creature_template` SET `faction`=1768 WHERE `entry`=101632;
@@ -0,0 +1,53 @@
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105176;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105169;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105168;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105171;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105170;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111079;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=90688;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111154;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111089;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=91902;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105166;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105163;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111165;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111153;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111152;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111149;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111148;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=92558;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105192;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105188;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105190;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105185;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105187;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105186;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105181;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105180;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105182;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105179;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111167;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111156;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111088;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111087;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105197;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105189;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111173;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111175;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111174;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105183;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105175;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105174;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105165;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105164;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111157;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111155;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111085;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=111171;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105196;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105167;
UPDATE `creature_template` SET `unit_flags`=33555200 WHERE `entry`=113129;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=90544;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=105172;
UPDATE `creature_template` SET `unit_flags`=33536 WHERE `entry`=94276;
UPDATE `creature_template` SET `unit_flags`=537166592 WHERE `entry`=101632;
@@ -0,0 +1,67 @@
UPDATE `creature_template` SET `unit_flags2`=2097152 WHERE `entry`=90686;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=97525;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=112920;
UPDATE `creature_template` SET `unit_flags2`=2097152 WHERE `entry`=100959;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=97527;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=112977;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113054;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113055;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=102706;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113058;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=97528;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=94191;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113056;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113057;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113053;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=94190;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=94189;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=91970;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=102701;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113059;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=105217;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=110941;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=94223;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=97502;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=102698;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=91949;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=92122;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=97503;
UPDATE `creature_template` SET `unit_flags2`=2097152 WHERE `entry`=92121;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=94209;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=110615;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=97526;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=113290;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=108990;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=112921;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=97521;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=93704;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=110614;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=102704;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=102703;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=102705;
UPDATE `creature_template` SET `unit_flags2`=2097152 WHERE `entry`=109591;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=113036;
UPDATE `creature_template` SET `unit_flags2`=2097152 WHERE `entry`=109604;
UPDATE `creature_template` SET `unit_flags2`=2097152 WHERE `entry`=109592;
UPDATE `creature_template` SET `unit_flags2`=2099201 WHERE `entry`=113291;
UPDATE `creature_template` SET `unit_flags2`=2131968 WHERE `entry`=113038;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90711;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90712;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90708;
UPDATE `creature_template` SET `unit_flags2`=2131968 WHERE `entry`=91588;
UPDATE `creature_template` SET `unit_flags2`=2131968 WHERE `entry`=109587;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=91353;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=97486;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=92586;
UPDATE `creature_template` SET `unit_flags2`=2113536 WHERE `entry`=92061;
UPDATE `creature_template` SET `unit_flags2`=2131968 WHERE `entry`=109586;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=101056;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90714;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=93219;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90710;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=97496;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=101057;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90717;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90705;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90713;
UPDATE `creature_template` SET `unit_flags2`=2099200 WHERE `entry`=90709;
+71
View File
@@ -0,0 +1,71 @@
name: sylvania-core
x-core: &core
build:
context: .
args:
BUILD_JOBS: ${BUILD_JOBS:-2}
BUILD_TYPE: ${BUILD_TYPE:-Release}
image: sylvania-core:${IMAGE_TAG:-local}
working_dir: /opt/sylvania/bin
restart: unless-stopped
depends_on:
database:
condition: service_healthy
environment:
DB_HOST: database
DB_PORT: 3306
DB_USER: ${DB_USER:-sylvania}
DB_PASSWORD: ${DB_PASSWORD:-sylvania}
REALM_NAME: ${REALM_NAME:-Sylvania Solo}
REALM_ADDRESS: ${REALM_ADDRESS:-127.0.0.1}
REALM_PORT: ${REALM_PORT:-8086}
volumes:
- ./data:/opt/sylvania/data:ro
- ./sql:/src/sql:ro
- sylvania-logs:/opt/sylvania/logs
services:
database:
image: mariadb:11.4
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-change-me}
DB_USER: ${DB_USER:-sylvania}
DB_PASSWORD: ${DB_PASSWORD:-sylvania}
volumes:
- database-data:/var/lib/mysql
- ./docker/database/init.sh:/docker-entrypoint-initdb.d/00-sylvania-init.sh:ro
- ./sql/base:/sylvania/base:ro
- ./docker/db-dumps:/sylvania/dumps:ro
healthcheck:
test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
interval: 5s
timeout: 5s
retries: 30
start_period: 30s
bnetserver:
<<: *core
command: ["bnetserver"]
environment:
DB_HOST: database
DB_PORT: 3306
DB_USER: ${DB_USER:-sylvania}
DB_PASSWORD: ${DB_PASSWORD:-sylvania}
EXTERNAL_ADDRESS: ${EXTERNAL_ADDRESS:-127.0.0.1}
ports:
- "1119:1119"
- "8081:8081"
worldserver:
<<: *core
command: ["worldserver"]
stdin_open: true
tty: true
ports:
- "${REALM_PORT:-8086}:8085"
volumes:
database-data:
sylvania-logs:
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -euo pipefail
db_user="${DB_USER:-sylvania}"
db_password="${DB_PASSWORD:-sylvania}"
# Identifiers are deliberately fixed; only the application login is configurable.
mariadb --protocol=socket -uroot -p"${MARIADB_ROOT_PASSWORD}" <<SQL
CREATE DATABASE IF NOT EXISTS auth CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE IF NOT EXISTS characters CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE IF NOT EXISTS world CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE IF NOT EXISTS hotfixes CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE IF NOT EXISTS shop CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE USER IF NOT EXISTS '${db_user}'@'%' IDENTIFIED BY '${db_password}';
GRANT ALL PRIVILEGES ON auth.* TO '${db_user}'@'%';
GRANT ALL PRIVILEGES ON characters.* TO '${db_user}'@'%';
GRANT ALL PRIVILEGES ON world.* TO '${db_user}'@'%';
GRANT ALL PRIVILEGES ON hotfixes.* TO '${db_user}'@'%';
GRANT ALL PRIVILEGES ON shop.* TO '${db_user}'@'%';
FLUSH PRIVILEGES;
SQL
mariadb --protocol=socket -uroot -p"${MARIADB_ROOT_PASSWORD}" auth < /sylvania/base/auth_database.sql
mariadb --protocol=socket -uroot -p"${MARIADB_ROOT_PASSWORD}" characters < /sylvania/base/characters_database.sql
mariadb --protocol=socket -uroot -p"${MARIADB_ROOT_PASSWORD}" shop < /sylvania/base/shop_database.sql
shopt -s nullglob
for dump in /sylvania/dumps/*.sql /sylvania/dumps/*.sql.gz; do
echo "Importing game database dump: ${dump}"
if [[ "${dump}" == *.gz ]]; then
gzip -dc "${dump}" | mariadb --protocol=socket -uroot -p"${MARIADB_ROOT_PASSWORD}"
else
mariadb --protocol=socket -uroot -p"${MARIADB_ROOT_PASSWORD}" < "${dump}"
fi
done
# The published 7.3.5 dump uses a lowercase name, while the core queries this
# one legacy table with its historical mixed-case identifier on Linux.
mariadb --protocol=socket -uroot -p"${MARIADB_ROOT_PASSWORD}" \
-e 'RENAME TABLE hotfixes.questv2clitask TO hotfixes.QuestV2CliTask;'
+13
View File
@@ -0,0 +1,13 @@
# Full game database dumps
Put the upstream `world` and `hotfixes` dumps here before the first
`docker compose up`. Both plain `.sql` and `.sql.gz` files are imported.
The repository intentionally does not ship those datasets. Do not use
`sql/base/dev`: those files contain empty developer schemas and are not a
playable game database.
If the database volume has already been initialized, add the dumps manually or
recreate the volume explicitly with `docker compose down -v` (this deletes all
database data).
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
set -euo pipefail
server="${1:-worldserver}"
case "${server}" in
worldserver|bnetserver) ;;
*) exec "$@" ;;
esac
db_host="${DB_HOST:-database}"
db_port="${DB_PORT:-3306}"
db_user="${DB_USER:-sylvania}"
db_password="${DB_PASSWORD:-sylvania}"
external_address="${EXTERNAL_ADDRESS:-127.0.0.1}"
realm_name="${REALM_NAME:-Sylvania Solo}"
realm_address="${REALM_ADDRESS:-127.0.0.1}"
realm_port="${REALM_PORT:-8086}"
if [[ ! "${realm_name}" =~ ^[[:alnum:]А-Яа-яЁё._[:space:]-]{1,32}$ ]]; then
echo "REALM_NAME contains unsupported characters or is longer than 32 characters" >&2
exit 1
fi
if [[ ! "${realm_address}" =~ ^[A-Za-z0-9.-]+$ ]]; then
echo "REALM_ADDRESS must be an IPv4 address or a DNS name" >&2
exit 1
fi
if [[ ! "${realm_port}" =~ ^[0-9]+$ ]] || (( realm_port < 1 || realm_port > 65535 )); then
echo "REALM_PORT must be an integer between 1 and 65535" >&2
exit 1
fi
config_dir=/opt/sylvania/etc
template="${config_dir}/${server}.conf.dist"
config="${config_dir}/${server}.conf"
cp "${template}" "${config}"
sed -i -E \
-e "s#^(LoginDatabaseInfo[[:space:]]*=).*#\\1 \"${db_host};${db_port};${db_user};${db_password};auth\"#" \
"${config}"
# Keep the client-facing realm record in sync after restores and migrations.
# Values are validated above before being interpolated into SQL.
mariadb --protocol=tcp \
-h "${db_host}" -P "${db_port}" -u "${db_user}" "-p${db_password}" auth <<SQL
INSERT INTO realmlist
(id, name, address, localAddress, localSubnetMask, port, icon, flag,
timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup)
VALUES
(1, '${realm_name}', '${realm_address}', '${realm_address}',
'255.255.255.0', ${realm_port}, 0, 0, 1, 0, 0, 26972, 1, 1)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
address = VALUES(address),
localAddress = VALUES(localAddress),
port = VALUES(port),
gamebuild = VALUES(gamebuild);
SQL
if [[ "${server}" == worldserver ]]; then
sed -i -E \
-e "s#^(WorldDatabaseInfo[[:space:]]*=).*#\\1 \"${db_host};${db_port};${db_user};${db_password};world\"#" \
-e "s#^(CharacterDatabaseInfo[[:space:]]*=).*#\\1 \"${db_host};${db_port};${db_user};${db_password};characters\"#" \
-e "s#^(HotfixDatabaseInfo[[:space:]]*=).*#\\1 \"${db_host};${db_port};${db_user};${db_password};hotfixes\"#" \
-e "s#^(ShopDatabaseInfo[[:space:]]*=).*#\\1 \"${db_host};${db_port};${db_user};${db_password};shop\"#" \
-e 's#^DataDir[[:space:]]*=.*#DataDir = "/opt/sylvania/data"#' \
-e 's#^LogsDir[[:space:]]*=.*#LogsDir = "/opt/sylvania/logs"#' \
"${config}"
else
sed -i -E \
-e "s#^LoginREST.ExternalAddress=.*#LoginREST.ExternalAddress=${external_address}#" \
-e "s#^LoginREST.LocalAddress=.*#LoginREST.LocalAddress=${external_address}#" \
-e 's#^LogsDir[[:space:]]*=.*#LogsDir = "/opt/sylvania/logs"#' \
"${config}"
fi
exec "/opt/sylvania/bin/${server}" -c "${config}"
+48
View File
@@ -0,0 +1,48 @@
-- =====================================================================
-- Rivage brisé (carte 1460) — factions démoniaques ramenées à 16
--
-- ÉTABLI PAR TEST A/B, pas par raisonnement.
-- Une seule entrée a été basculée en faction 16 — le Molosse de l'effroi
-- gangrené (90686) — toutes choses égales par ailleurs. Résultat en jeu :
-- « les molosses sont maintenant attaquables », les autres non.
--
-- La sonde SPAWNDBG confirme que seule la faction distingue les deux :
-- Felstalker Dreadhound faction=16 drapeaux=32768 drapeaux2=0 → OK
-- Felguard Legionnaire faction=2780 drapeaux=32768 drapeaux2=0 → bloqué
-- Mêmes drapeaux, même niveau, même vie, mêmes phases.
--
-- POURQUOI 2780 ÉCHOUE, ALORS QUE LA THÉORIE DIT L'INVERSE
-- `FactionTemplate.db2` donne pour 2780 : Faction=1786, EnemyGroup=15,
-- soit ennemi de tous les groupes, joueurs compris. Et 1786 (« Burning
-- Legion Invaders ») a ReputationIndex=-1, donc aucune réputation
-- n'intervient. Sur le papier, 2780 devrait être hostile.
--
-- Elle ne l'est pas dans les faits, et je n'ai pas élucidé pourquoi. Le
-- refus vient du client, qui n'interroge jamais le serveur — aucune sonde
-- côté serveur ne peut l'observer.
--
-- CHOIX ASSUMÉ : on retient la faction 16, qui fonctionne de façon
-- démontrée dans ce scénario même — c'est celle qu'emploient les démons
-- invoqués par le script. C'est un écart avec la donnée de référence,
-- consenti parce qu'il rend le contenu jouable.
--
-- Effet secondaire bienvenu : les démons cessent de s'entretuer. La
-- faction 16 les rend amis entre eux (Friend_0=14), ce qui met fin au
-- « démons inattaquables qui se battent avec les attaquables ».
--
-- PORTÉE : uniquement les entrées exclusives à la carte 1460, comme pour
-- les correctifs précédents. Les entrées partagées avec d'autres cartes
-- sont écartées.
--
-- Retour arrière : chantiers/rivage_brise/retour_faction16_1460.sql
-- =====================================================================
UPDATE `creature_template` ct
JOIN (SELECT DISTINCT c.id
FROM creature c
JOIN creature_template t ON t.entry = c.id
WHERE c.map = 1460
AND t.faction IN (2780, 1768)
AND c.id NOT IN (SELECT DISTINCT id FROM creature WHERE map <> 1460)) AS cible
ON cible.id = ct.entry
SET ct.faction = 16;
+46
View File
@@ -0,0 +1,46 @@
-- =====================================================================
-- Rivage brisé (carte 1460) — retrait de l'immunité aux joueurs
--
-- Signalé en jeu : « les démons invoqués c'est ok mais pas les autres
-- au fond ». Les créatures invoquées par le script étaient frappables,
-- les placements statiques non.
--
-- LA CAUSE, et elle est de mon fait
-- La transposition des modèles de créatures depuis le dump de référence
-- a importé `unit_flags` sur 136 entrées. Parmi les valeurs reprises,
-- 33536 et 537166592 contiennent le bit 256 — UNIT_FLAG_IMMUNE_TO_PC,
-- qui empêche tout joueur d'attaquer la créature.
--
-- Dans le cœur de référence, un script retire vraisemblablement ce
-- drapeau à l'instant voulu. Le nôtre ne gère aucun drapeau : les
-- démons restaient donc immunisés en permanence.
--
-- Cela explique aussi pourquoi la sonde ATTDBG ne produisait plus rien :
-- le client refusait de lui-même, sans jamais interroger le serveur.
--
-- PORTÉE : uniquement les factions HOSTILES —
-- 2780 (30 entrées), 1768 (20 : Anetheron, Balnazzar, Brutallus…),
-- 2878 (Krosus), 14 (Gul'dan), 2877 (Lave gangrenée).
--
-- Volontairement ÉPARGNÉS, car l'immunité y est légitime :
-- 35, 2876, 2879, 1819 — alliés, prêtres, montures, vaisseaux.
--
-- UNE SIMPLIFICATION ASSUMÉE
-- Krosus et Gul'dan perdent aussi leur immunité, alors qu'une
-- implémentation fidèle la retirerait au début de leur étape. Notre
-- script ne gère aucun drapeau : la conserver rendrait les étapes 7 et 8
-- infranchissables. La progression reste pilotée par la machine à états
-- du script.
--
-- Retour arrière : chantiers/rivage_brise/retour_immunite_1460.sql
-- =====================================================================
UPDATE `creature_template` ct
JOIN (SELECT DISTINCT c.id
FROM creature c
JOIN creature_template t ON t.entry = c.id
WHERE c.map = 1460
AND (t.unit_flags & 256)
AND t.faction IN (2780, 1768, 2877, 2878, 14)) AS cible
ON cible.id = ct.entry
SET ct.unit_flags = ct.unit_flags & ~256;
+42
View File
@@ -0,0 +1,42 @@
-- =====================================================================
-- Rivage brisé (carte 1460) — retrait du drapeau UNIT_FLAG2_UNK5
--
-- Signalé en jeu : « les démons invoqués c'est ok mais pas les autres au
-- fond », puis « les fameux démons inattaquables se battent avec les
-- démons attaquables ». Nommément : Gangreseigneur Rakkan, Légionnaire
-- gangregarde, Molosse de l'effroi gangrené.
--
-- LA CAUSE, et elle est de mon fait
-- La transposition des modèles depuis le dump de référence a importé
-- `unit_flags2` sur 147 entrées. Ces trois-là valaient 0 avant ; elles
-- ont reçu 2097152, soit 0x200000 — UNIT_FLAG2_UNK5 dans notre cœur.
--
-- CE QUI REND CE DRAPEAU PARTICULIER : notre serveur l'IGNORE
-- totalement. Aucune de ses vérifications ne le consulte. Mais le client,
-- lui, l'interprète et refuse de désigner la créature comme cible.
--
-- C'est ce qui explique le symptôme le plus déroutant de la série : une
-- sonde posée dans `Unit::_IsValidAttackTarget` n'a JAMAIS produit la
-- moindre ligne pour ces créatures. Le client refusait de lui-même, sans
-- jamais interroger le serveur. L'absence de trace était l'information.
--
-- LA CORRÉLATION QUI TRANCHE
-- démons INVOQUÉS par le script (attaquables) : unit_flags2 = 0
-- démons STATIQUES (bloqués) : bit 0x200000 présent
-- 67 entrées, 420 spawns concernés
--
-- On retire UNIQUEMENT ce bit, en préservant le reste de la colonne.
-- Le serveur ne s'en sert pas : ce retrait ne peut rien casser côté
-- logique, il lève seulement le refus du client.
--
-- Retour arrière : chantiers/rivage_brise/retour_unk5_1460.sql
-- =====================================================================
UPDATE `creature_template` ct
JOIN (SELECT DISTINCT c.id
FROM creature c
JOIN creature_template t ON t.entry = c.id
WHERE c.map = 1460
AND (t.unit_flags2 & 2097152)) AS cible
ON cible.id = ct.entry
SET ct.unit_flags2 = ct.unit_flags2 & ~2097152;
+34
View File
@@ -0,0 +1,34 @@
# Русская локализация Legion 7.3.5
Пакет добавляет 37 773 отсутствующие строки `ruRU` в таблицу
`broadcast_text_locale`. Переводы взяты из ветки `legion` проекта
AshamaneCore и адаптированы к текущей схеме SylvaniaCore:
- `MaleText_lang` → `Text_lang`
- `FemaleText_lang` → `Text1_lang`
Файлы используют `INSERT IGNORE`: уже существующие строки не изменяются.
Импортировать их нужно по порядку в базу `hotfixes`:
```bash
set -a
. ./.env
set +a
for file in sql/translations/ruRU/broadcast_text_locale_ruRU_part_*.sql; do
docker compose exec -T database \
mariadb --binary-mode -uroot "-p${DB_ROOT_PASSWORD}" hotfixes < "$file"
done
```
После импорта перезапустите игровой сервер:
```bash
docker compose restart worldserver
```
Перед установкой на рабочий сервер рекомендуется сделать резервную копию БД.
Таблицы `creature_template_locale`, `quest_template_locale` и
`quest_objectives_locale` уже содержат все русские строки из указанного
источника, поэтому для них SQL-дельта не требуется.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
-- Production realm defaults. Docker startup keeps these values synchronized
-- from REALM_NAME, REALM_ADDRESS and REALM_PORT after this migration runs.
UPDATE `realmlist`
SET `name` = 'FelWell',
`address` = 'legion.moon-well.online',
`localAddress` = 'legion.moon-well.online',
`port` = 8085,
`gamebuild` = 26972
WHERE `id` = 1;
@@ -1574,6 +1574,29 @@ bool Creature::LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool ad
GetMap()->AddBattlePet(this); GetMap()->AddBattlePet(this);
// SONDE TEMPORAIRE - carte 1460. Etat REEL en memoire une fois la
// creature entierement chargee depuis la base, pour le comparer a ce
// que dit la table. Une sur dix : il y en a 757.
//
// La version precedente etait posee dans un bloc de rechargement que
// ce chemin n'emprunte jamais -- elle n'a produit aucune ligne.
if (GetMapId() == 1460)
{
static uint32 sondeSpawn = 0;
if ((++sondeSpawn % 10) == 1)
{
TC_LOG_ERROR("misc",
"SPAWNDBG %s (entree %u) | faction=%u niveau=%u | pv=" UI64FMTD "/" UI64FMTD
" | vivante=%u | drapeaux=%u drapeaux2=%u dynamiques=%u | phases=%u",
GetName().c_str(), GetEntry(), getFaction(), getLevel(),
GetHealth(), GetMaxHealth(),
uint32(IsAlive() ? 1 : 0),
GetUInt32Value(UNIT_FIELD_FLAGS), GetUInt32Value(UNIT_FIELD_FLAGS_2),
GetUInt32Value(OBJECT_DYNAMIC_FLAGS),
uint32(GetPhaseShift().GetPhases().size()));
}
}
return true; return true;
} }
@@ -3336,6 +3359,7 @@ void Creature::ReLoad(bool skipDB)
if (IsAIEnabled) if (IsAIEnabled)
AI()->EnterEvadeMode(); AI()->EnterEvadeMode();
TC_LOG_DEBUG("sql.sql", "Creature SpawnID (" SI64FMTD ") reloaded.", GetSpawnId()); TC_LOG_DEBUG("sql.sql", "Creature SpawnID (" SI64FMTD ") reloaded.", GetSpawnId());
} }
+36
View File
@@ -8314,6 +8314,42 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
{ {
ASSERT(target); ASSERT(target);
// SONDE TEMPORAIRE - carte 1460 uniquement, et seulement quand un
// JOUEUR vise une CREATURE. Volume borne : quelques lignes par seconde
// au plus, et uniquement dans ce scenario.
if (GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_UNIT && GetMapId() == 1460)
{
// On ne veut QUE les demons statiques : factions 2780 et 1768.
// Les invoques (faction 16) fonctionnent deja et polluaient le
// releve.
uint32 const factionCible = target->getFaction();
static uint32 sondeAtt = 0;
if ((factionCible == 2780 || factionCible == 1768) && (++sondeAtt % 5) == 1)
{
TC_LOG_ERROR("misc",
"ATTDBG cible %s (entree %u) | vivante=%u etatInattaquable=%u | drapeaux=%u "
"(NON_ATTACKABLE=%u NOT_ATTACKABLE_1=%u UNK_16=%u IMMUNE_PC=%u NOT_SELECTABLE=%u) "
"| reaction=%d | jeLaVois=%u | mesPhases=%u sesPhases=%u "
"| factionCible=%u maFaction=%u | elleMEstHostile=%u jeLuiSuisHostile=%u",
target->GetName().c_str(), target->GetEntry(),
uint32(target->IsAlive() ? 1 : 0),
uint32(target->HasUnitState(UNIT_STATE_UNATTACKABLE) ? 1 : 0),
target->GetUInt32Value(UNIT_FIELD_FLAGS),
uint32(target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) ? 1 : 0),
uint32(target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_1) ? 1 : 0),
uint32(target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_16) ? 1 : 0),
uint32(target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) ? 1 : 0),
uint32(target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) ? 1 : 0),
int32(GetReactionTo(target)),
uint32(CanSeeOrDetect(target, true) ? 1 : 0),
uint32(GetPhaseShift().GetPhases().size()),
uint32(target->GetPhaseShift().GetPhases().size()),
factionCible, getFaction(),
uint32(target->IsHostileTo(this) ? 1 : 0),
uint32(IsHostileTo(target) ? 1 : 0));
}
}
// can't attack self // can't attack self
if (this == target) if (this == target)
return false; return false;
+14 -1
View File
@@ -350,7 +350,20 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
///- Before we process anything: ///- Before we process anything:
/// If necessary, kick the player from the character select screen /// If necessary, kick the player from the character select screen
if (!IsBotSession() && IsConnectionIdle()) //
// SylvaniaCore : les comptes de niveau superieur a SEC_PLAYER --
// maitres de jeu, testeurs, administration -- ne sont plus coupes
// pour inactivite.
//
// Motif : ces comptes restent volontairement connectes de longues
// minutes sans emettre de paquet, le temps d'observer une zone, de
// suivre un evenement scripte ou d'attendre le resultat d'un test.
// Le delai de SocketTimeOutTime (900 s) les deconnectait en plein
// travail, parfois au milieu d'une instance.
//
// Les joueurs ordinaires restent soumis au delai : la protection
// contre les sessions fantomes conserve tout son interet pour eux.
if (!IsBotSession() && GetSecurity() <= SEC_PLAYER && IsConnectionIdle())
m_Socket[CONNECTION_TYPE_REALM]->CloseSocket(); m_Socket[CONNECTION_TYPE_REALM]->CloseSocket();
///- Retrieve packets from the receive queue and call the appropriate handlers ///- Retrieve packets from the receive queue and call the appropriate handlers
@@ -172,7 +172,30 @@ struct scenario_broken_shore_intro : public InstanceScript
if (player->GetMapId() != 1460) if (player->GetMapId() != 1460)
return; return;
PhasingHandler::AddPhase(player, PHASE_NORMAL, true); // ==========================================================
// SylvaniaCore : phasage retire.
//
// SIGNALE EN JEU : les creatures etaient visibles, hostiles, mais
// impossibles a cibler. Une sonde posee dans _IsValidAttackTarget
// a donne le verdict :
// reaction=1 (hostile), aucun drapeau bloquant, vivante,
// mesPhases=0 sesPhases=1
//
// Deux objets ne se voient que s'ils PARTAGENT une phase
// (PhaseShift::CanSee, intersection des phases), et
// UpdateUnphasedFlag retire le statut « non phase » des qu'un
// objet en possede une. Le joueur n'en avait aucune : aucune
// intersection possible.
//
// Le phasage etait de toute facon une invention locale : le dump
// de reference laisse les 757 placements de cette carte SANS
// phase (PhaseId vide). On revient donc a cette configuration --
// tout le monde non phase, tout le monde se voit.
//
// La phase 169 n'existe d'ailleurs pas dans Phase.db2 du build
// 7.3.5.26972, ce qui la rendait d'autant plus douteuse.
// ==========================================================
// objectif « embarquement » (Alliance) : credite aussi ici au cas ou // objectif « embarquement » (Alliance) : credite aussi ici au cas ou
player->KilledMonsterCredit(NPC_CREDIT_SHIP); player->KilledMonsterCredit(NPC_CREDIT_SHIP);
@@ -207,10 +230,13 @@ struct scenario_broken_shore_intro : public InstanceScript
// Toute invocation doit partager la phase des joueurs (OnPlayerEnter les met en 169), // Toute invocation doit partager la phase des joueurs (OnPlayerEnter les met en 169),
// sinon elle est invisible/intangible : cible de quete introuvable, vague intuable. // sinon elle est invisible/intangible : cible de quete introuvable, vague intuable.
// (defaut systemique detecte par le harnais bot le 26/07, deja corrige dans le runner d artefacts) // (defaut systemique detecte par le harnais bot le 26/07, deja corrige dans le runner d artefacts)
// SylvaniaCore : ne phase plus rien. Laisser la phase 169 ici alors
// que le joueur n'en a aucune rendrait les invocations invisibles --
// le probleme meme qu'on vient de corriger, en sens inverse.
// Conservee comme point de passage unique pour les invocations, au
// cas ou un traitement commun redevienne necessaire.
TempSummon* FinalizeSummon(TempSummon* summon) const TempSummon* FinalizeSummon(TempSummon* summon) const
{ {
if (summon)
PhasingHandler::AddPhase(summon, PHASE_NORMAL, true);
return summon; return summon;
} }
@@ -337,6 +363,27 @@ struct scenario_broken_shore_intro : public InstanceScript
} }
break; break;
default: default:
// =====================================================
// SylvaniaCore : tout demon compte pour l objectif.
//
// SIGNALE EN JEU : « les molosses sont maintenant
// attaquables mais ne comptent pas dans l objectif du
// scenario ».
//
// Le script ne reconnaissait que les CINQ entrees qu il
// invoque lui-meme. Or la carte porte 101 entrees de
// demons placees, affrontees tout au long de l assaut :
// elles ne crediraient rien.
//
// Plutot que d enumerer 101 entrees -- liste qui
// vieillirait mal --, on s appuie sur la donnee : le type
// demon. Tous les demons de cette carte sont desormais
// hostiles (faction 16). Les Seigneurs gangrebois,
// Arganoth, Krosus et Gul dan sont traites avant et n
// arrivent jamais ici : ils ont leurs propres criteres.
// =====================================================
if (creature->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON)
OnDemonDied();
break; break;
} }
} }
+38 -2
View File
@@ -805,8 +805,37 @@ public:
static bool HandleNpcNearCommand(ChatHandler* handler, char const* args) static bool HandleNpcNearCommand(ChatHandler* handler, char const* args)
{ {
// =============================================================
// SylvaniaCore : .npc near faisait tomber le serveur.
//
// SIGNALE EN JEU : « la commande .npc near fait planter le
// serveur ». La requete preparee WORLD_SEL_CREATURE_NEAREST n'a
// AUCUNE limite : elle calcule trois puissances sur les 384 000
// lignes de la table creature, sans index utilisable, puis la
// boucle ci-dessous envoie UN message de discussion par resultat.
// Avec un rayon large, cela represente des dizaines de milliers
// de paquets pour une seule commande.
//
// Deux garde-fous, la requete etant partagee avec d'autres
// commandes :
// - le rayon est plafonne ;
// - le nombre de lignes affichees l'est aussi, et l'on ANNONCE
// combien ont ete omises plutot que de tronquer en silence.
// =============================================================
float const RAYON_MAX = 500.0f;
uint32 const LIGNES_MAX = 150;
float distance = (!*args) ? 10.0f : float((atof(args))); float distance = (!*args) ? 10.0f : float((atof(args)));
if (distance > RAYON_MAX)
{
handler->PSendSysMessage("Rayon ramene de %.0f a %.0f : au-dela la recherche parcourt toute la table et sature la session.", distance, RAYON_MAX);
distance = RAYON_MAX;
}
if (distance <= 0.0f)
distance = 10.0f;
uint32 count = 0; uint32 count = 0;
uint32 omises = 0;
Player* player = handler->GetSession()->GetPlayer(); Player* player = handler->GetSession()->GetPlayer();
@@ -838,14 +867,21 @@ public:
if (!creatureTemplate) if (!creatureTemplate)
continue; continue;
handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), creatureTemplate->Name.c_str(), x, y, z, o, mapId);
++count; ++count;
if (count > LIGNES_MAX)
{
++omises;
continue;
}
handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), creatureTemplate->Name.c_str(), x, y, z, o, mapId);
} }
while (result->NextRow()); while (result->NextRow());
} }
handler->PSendSysMessage(LANG_COMMAND_NEAR_NPC_MESSAGE, distance, count); handler->PSendSysMessage(LANG_COMMAND_NEAR_NPC_MESSAGE, distance, count);
if (omises)
handler->PSendSysMessage("%u resultats supplementaires non affiches, plafond %u. Reduisez le rayon pour les voir.", omises, LIGNES_MAX);
return true; return true;
} }
@@ -57,7 +57,20 @@ public:
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{ {
ClearGossipMenuFor(player); ClearGossipMenuFor(player);
hyjalAI* ai = ENSURE_AI(hyjalAI, creature->AI()); // SylvaniaCore : ENSURE_AI faisait tomber TOUT le serveur.
//
// GetAI() ne fabrique une hyjalAI que si GetHyjalAI() la trouve,
// c est-a-dire dans l instance du Mont Hyjal. Ailleurs la creature
// recoit une IA quelconque -- et ENSURE_AI, qui ASSERTE, tuait le
// process. Constate en production : un exemplaire de Jaina (17772)
// se trouvait sur la carte 0, a Hurlevent ; lui parler suffisait a
// planter le serveur (SIGSEGV dans Trinity::Assert, appele depuis
// npc_jaina_proudmoore::OnGossipHello).
//
// On echoue desormais proprement : le PNJ ne repond simplement pas.
hyjalAI* ai = dynamic_cast<hyjalAI*>(creature->AI());
if (!ai)
return false;
switch (action) switch (action)
{ {
case GOSSIP_ACTION_INFO_DEF + 1: case GOSSIP_ACTION_INFO_DEF + 1:
@@ -81,7 +94,20 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override bool OnGossipHello(Player* player, Creature* creature) override
{ {
hyjalAI* ai = ENSURE_AI(hyjalAI, creature->AI()); // SylvaniaCore : ENSURE_AI faisait tomber TOUT le serveur.
//
// GetAI() ne fabrique une hyjalAI que si GetHyjalAI() la trouve,
// c est-a-dire dans l instance du Mont Hyjal. Ailleurs la creature
// recoit une IA quelconque -- et ENSURE_AI, qui ASSERTE, tuait le
// process. Constate en production : un exemplaire de Jaina (17772)
// se trouvait sur la carte 0, a Hurlevent ; lui parler suffisait a
// planter le serveur (SIGSEGV dans Trinity::Assert, appele depuis
// npc_jaina_proudmoore::OnGossipHello).
//
// On echoue desormais proprement : le PNJ ne repond simplement pas.
hyjalAI* ai = dynamic_cast<hyjalAI*>(creature->AI());
if (!ai)
return false;
if (ai->EventBegun) if (ai->EventBegun)
return false; return false;
@@ -136,7 +162,20 @@ public:
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{ {
ClearGossipMenuFor(player); ClearGossipMenuFor(player);
hyjalAI* ai = ENSURE_AI(hyjalAI, creature->AI()); // SylvaniaCore : ENSURE_AI faisait tomber TOUT le serveur.
//
// GetAI() ne fabrique une hyjalAI que si GetHyjalAI() la trouve,
// c est-a-dire dans l instance du Mont Hyjal. Ailleurs la creature
// recoit une IA quelconque -- et ENSURE_AI, qui ASSERTE, tuait le
// process. Constate en production : un exemplaire de Jaina (17772)
// se trouvait sur la carte 0, a Hurlevent ; lui parler suffisait a
// planter le serveur (SIGSEGV dans Trinity::Assert, appele depuis
// npc_jaina_proudmoore::OnGossipHello).
//
// On echoue desormais proprement : le PNJ ne repond simplement pas.
hyjalAI* ai = dynamic_cast<hyjalAI*>(creature->AI());
if (!ai)
return false;
ai->DeSpawnVeins();//despawn the alliance veins ai->DeSpawnVeins();//despawn the alliance veins
switch (action) switch (action)
{ {
@@ -161,7 +200,20 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override bool OnGossipHello(Player* player, Creature* creature) override
{ {
hyjalAI* ai = ENSURE_AI(hyjalAI, creature->AI()); // SylvaniaCore : ENSURE_AI faisait tomber TOUT le serveur.
//
// GetAI() ne fabrique une hyjalAI que si GetHyjalAI() la trouve,
// c est-a-dire dans l instance du Mont Hyjal. Ailleurs la creature
// recoit une IA quelconque -- et ENSURE_AI, qui ASSERTE, tuait le
// process. Constate en production : un exemplaire de Jaina (17772)
// se trouvait sur la carte 0, a Hurlevent ; lui parler suffisait a
// planter le serveur (SIGSEGV dans Trinity::Assert, appele depuis
// npc_jaina_proudmoore::OnGossipHello).
//
// On echoue desormais proprement : le PNJ ne repond simplement pas.
hyjalAI* ai = dynamic_cast<hyjalAI*>(creature->AI());
if (!ai)
return false;
if (ai->EventBegun) if (ai->EventBegun)
return false; return false;
@@ -244,7 +296,20 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override bool OnGossipHello(Player* player, Creature* creature) override
{ {
hyjalAI* ai = ENSURE_AI(hyjalAI, creature->AI()); // SylvaniaCore : ENSURE_AI faisait tomber TOUT le serveur.
//
// GetAI() ne fabrique une hyjalAI que si GetHyjalAI() la trouve,
// c est-a-dire dans l instance du Mont Hyjal. Ailleurs la creature
// recoit une IA quelconque -- et ENSURE_AI, qui ASSERTE, tuait le
// process. Constate en production : un exemplaire de Jaina (17772)
// se trouvait sur la carte 0, a Hurlevent ; lui parler suffisait a
// planter le serveur (SIGSEGV dans Trinity::Assert, appele depuis
// npc_jaina_proudmoore::OnGossipHello).
//
// On echoue desormais proprement : le PNJ ne repond simplement pas.
hyjalAI* ai = dynamic_cast<hyjalAI*>(creature->AI());
if (!ai)
return false;
uint32 AzgalorEvent = ai->GetInstanceData(DATA_AZGALOREVENT); uint32 AzgalorEvent = ai->GetInstanceData(DATA_AZGALOREVENT);
// Only let them get item if Azgalor is dead. // Only let them get item if Azgalor is dead.
@@ -4664,9 +4664,52 @@ pbotasl = 88
pbottitle = 600 pbottitle = 600
#
# pbotqa
# Description: Harnais d assurance qualite. Par defaut, un bot de terrain qui
# se retrouve sur une carte d instance est renvoye chez lui.
# A 1, il est autorise a y rester : cela permet d observer le
# comportement des bots en donjon sans qu ils soient rapatries.
# Ne pas activer en production.
# Default: 0 - (Desactive)
# 1 - (Actif)
pbotqa = 0
# #
#################################################################################################### ####################################################################################################
###################################################################################################
# CUSTOM SYLVANIA : BOND HEROIQUE
#
# Multiplicateurs appliques au saut du Bond heroique (sorts 94954 et 6544). Le saut
# EFFECTIF est porte par SPELL_EFFECT_DASH du sort 6544 en phase HIT, qui ecrase le
# JUMP_DEST de 94954 en phase LAUNCH : les deux identifiants sont donc traites, pour
# un ressenti coherent.
#
# Ces deux cles sont reglables A CHAUD via « .reload config », sans redemarrage.
#
# /!\ Ce sont des reglages de ressenti, pas des correctifs : la valeur Blizzlike est
# 1.0 pour les deux. Les defauts ci-dessous sont deja un boost assume, et le royaume
# va plus loin encore (2.8 / 4.0).
#
# HeroicLeap.SpeedMult
# Description: Facteur de vitesse horizontale (1.0 = Blizzlike, ~21 yd/s).
# Default: 1.7
HeroicLeap.SpeedMult = 1.7
#
# HeroicLeap.HeightMult
# Description: Facteur de hauteur d arc (1.0 = Blizzlike, 2.5 -> 10 yd).
# Default: 2.5
HeroicLeap.HeightMult = 2.5
#
###################################################################################################
################################################################################################### ###################################################################################################
# MODULE SIEGE DES CAPITALES (SylvaniaCore) # MODULE SIEGE DES CAPITALES (SylvaniaCore)
# #
@@ -4910,3 +4953,100 @@ siege_horde_route_last = 2099
# #
################################################################################################### ###################################################################################################
###################################################################################################
# MODULE MERCENAIRES (SylvaniaCore)
#
# Le Portail d Invocation de Mercenaire (creature 1000010) loue des playerbots
# au joueur, contre or et sans aucune garantie de duree : quitter le groupe,
# renvoyer le mercenaire ou se deconnecter rompt le contrat sur-le-champ.
#
# pbotmerc
# Description: Active le module.
# Default: 0 - (Desactive)
# 1 - (Actif)
pbotmerc = 0
#
# pbotmerc_cost
# Description: Prix d une invocation, en pieces d or.
# Default: 100
pbotmerc_cost = 100
#
# pbotmerc_max
# Description: Nombre de mercenaires simultanes par joueur. Un groupe
# compte cinq places, maitre inclus : au-dela de 4 il
# faudrait convertir le groupe en raid, ce qui interdirait
# les donjons. La valeur est donc plafonnee a 4.
# Default: 4
pbotmerc_max = 4
#
# pbotmerc_minlevel
# Description: Niveau minimum du joueur pour employer un mercenaire.
# Default: 10
pbotmerc_minlevel = 10
#
###################################################################################################
###################################################################################################
# MODULE MERCENAIRES - VOLET CONVERSATION (SylvaniaCore)
#
# Le mercenaire parle par l intermediaire du modele de langage de son
# employeur, avec la cle d API de celui-ci. La cle n est jamais enregistree :
# elle vit en memoire le temps du contrat et disparait a sa rupture.
# Le joueur la fournit en jeu par « !api <fournisseur> <modele> <cle> ».
#
# pbotmerc_chat
# Description: Active le dialogue par modele de langage.
# Default: 0 - (Desactive)
# 1 - (Actif)
pbotmerc_chat = 0
#
# pbotmerc_chat_cooldown
# Description: Delai minimum, en secondes, entre deux repliques payees par
# un meme joueur. Garde-fou contre les macros bavardes.
# Default: 5
pbotmerc_chat_cooldown = 5
#
# pbotmerc_chat_timeout
# Description: Delai d expiration d un appel d API, en secondes.
# Default: 30
pbotmerc_chat_timeout = 30
#
# pbotmerc_chat_maxtokens
# Description: Longueur maximale de la reponse, en jetons. Le chat du
# client ne montre qu une ligne : inutile de voir grand.
# Default: 160
pbotmerc_chat_maxtokens = 160
#
# pbotmerc_chat_history
# Description: Nombre d echanges gardes en memoire par mercenaire. Chaque
# echange conserve est renvoye au modele, donc refacture.
# Default: 6
pbotmerc_chat_history = 6
#
# pbotmerc_chat_queue
# Description: Profondeur maximale de la file d appels en attente.
# Default: 32
pbotmerc_chat_queue = 32
#
###################################################################################################