From 7f8cdd2d4b429ef1b66ff02071916ff1aa94e0ed Mon Sep 17 00:00:00 2001 From: SylvaniaCore deploy Date: Thu, 27 Aug 2026 12:05:59 +0200 Subject: [PATCH] Scenarios : la verification de l etape doit etre purement lectrice Correctif du commit precedent, qui FAISAIT PLANTER LE SERVEUR. Il appelait CheckCompletedCriteriaTree sur l arbre racine. Enchainement du debordement de pile (SIGSEGV, vidage de 389 Mo contre 120 Mo en temps normal) : feuille achevee -> Scenario::CompletedCriteriaTree(feuille) -> CheckCompletedCriteriaTree(racine) -> operateur ALL : parcourt les enfants -> CheckCompletedCriteriaTree(enfant) -> enfant complet ET absent de _completedCriteriaTree -> CompletedCriteriaTree(enfant) ... et on reboucle. Le garde anti-reentrance existe pourtant (CriteriaHandler.cpp:1109), mais l insertion dans _completedCriteriaTree se fait dans CriteriaHandler::CompletedCriteriaTree -- que cette surcharge ne rappelle jamais. L arbre n est donc jamais enregistre et le garde ne se declenche pas. On se contente desormais de LIRE la progression via IsCompletedCriteria, en parcourant l arbre avec WalkCriteriaTree, sans jamais repasser par le moteur d evaluation. Plus aucun effet de bord, donc plus de reentrance. Co-Authored-By: Claude Opus 5 --- src/server/game/Scenarios/Scenario.cpp | 41 +++++++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/server/game/Scenarios/Scenario.cpp b/src/server/game/Scenarios/Scenario.cpp index 8302253..9c03a79 100644 --- a/src/server/game/Scenarios/Scenario.cpp +++ b/src/server/game/Scenarios/Scenario.cpp @@ -192,7 +192,7 @@ bool Scenario::CanCompleteCriteriaTree(CriteriaTree const* tree) return true; } -void Scenario::CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) +void Scenario::CompletedCriteriaTree(CriteriaTree const* tree, Player* /*referencePlayer*/) { ScenarioStepEntry const* step = tree->ScenarioStep; if (!step) @@ -233,10 +233,28 @@ void Scenario::CompletedCriteriaTree(CriteriaTree const* tree, Player* reference // la racine n'etant jamais transmise ici, l'etape ne s'acheverait // alors JAMAIS. // - // `CheckCompletedCriteriaTree` peut, en cas de succes, rappeler - // cette fonction avec la racine : on relit donc l'etat de l'etape - // ensuite, faute de quoi `CompleteStep` serait execute deux fois et - // la quete de recompense octroyee en double. + // LA VERIFICATION DOIT ETRE PUREMENT LECTRICE. + // + // Une premiere version appelait `CheckCompletedCriteriaTree` sur la + // racine. C'ETAIT UNE ERREUR, et elle a fait planter le serveur par + // debordement de pile (SIGSEGV, vidage de 389 Mo contre 120 Mo en + // temps normal). Enchainement : + // + // feuille achevee -> Scenario::CompletedCriteriaTree(feuille) + // -> CheckCompletedCriteriaTree(racine) + // -> operateur ALL : parcourt les enfants + // -> CheckCompletedCriteriaTree(enfant) + // -> enfant complet ET absent de _completedCriteriaTree + // -> CompletedCriteriaTree(enfant) ... et on reboucle. + // + // Le garde anti-reentrance existe pourtant (ligne 1109 de + // CriteriaHandler.cpp), mais l'insertion dans `_completedCriteriaTree` + // se fait dans `CriteriaHandler::CompletedCriteriaTree` -- que cette + // surcharge ne rappelle jamais. L'arbre n'est donc jamais enregistre + // et le garde ne se declenche pas. + // + // On se contente donc de LIRE la progression des criteres, sans + // jamais repasser par le moteur d'evaluation. // ================================================================= if (step->Criteriatreeid && step->Criteriatreeid != tree->Entry->ID) { @@ -244,10 +262,17 @@ void Scenario::CompletedCriteriaTree(CriteriaTree const* tree, Player* reference if (!racine) return; - if (!CheckCompletedCriteriaTree(racine, referencePlayer)) - return; + bool complet = true; + CriteriaMgr::WalkCriteriaTree(racine, [this, &complet](CriteriaTree const* noeud) + { + if (!complet || !noeud->Criteria) + return; - if (GetStepState(step) == SCENARIO_STEP_DONE) + if (!IsCompletedCriteria(noeud->Criteria, noeud->Entry->Amount)) + complet = false; + }); + + if (!complet) return; }