From 77648c6b53e26d293ffea8b1a678195699293796 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 30 Oct 2026 02:36:26 +0100 Subject: [PATCH] Preserve navigation fallbacks after early group departure --- doc/clientless/SESSION-RESUME.md | 55 +++++++++++++++++++ .../group-departure-and-instance-modes.md | 12 ++++ .../game/World/AdventureBehaviorMgr.cpp | 27 +++++++-- .../test_adventure_group_departure.py | 9 +++ 4 files changed, 97 insertions(+), 6 deletions(-) diff --git a/doc/clientless/SESSION-RESUME.md b/doc/clientless/SESSION-RESUME.md index 51609408f3..5ec69963d2 100644 --- a/doc/clientless/SESSION-RESUME.md +++ b/doc/clientless/SESSION-RESUME.md @@ -1,3 +1,58 @@ +# CURRENT FINDING / FIX IN BUILD: early snapshot repins travel fallbacks + +During observation initial full groups began early correctly, but when route +planning failed, UpdateDeparture kept overwriting normal fallback destination +with original copied goal every tick. Repeated GROUP_EARLY_DEPART/INSTANCE_PLAN +were retries, NOT additional successful departures. Preserved state +/tmp/vcore-group-observation-20261030/before-fallback-fix.json. Server never crashed. + +User informed and targeted fix+brief planned restart announced, preserving test +plans/groups. Changed ONLY BehaviorMgr.cpp +departure regression: applycopy only +while actual intent still formation/empty; GroupPlan and AdoptGroup use effective +Wanted fallback after application; leaving group keeps fallback within copied +intent. No new schema/header. Real production regression for repeatedmaintenance, +leaderfallback inheritance andkick added; departure+groupplan tests pass, intent +state targetedtest included in build command. Build-j10 running execsession82369, +log/tmp/vcore-group-fallback-build.log. Need wait buildfinish, commit fix, graceful +shutdown387859 andinstall/restart finalfix, no testDBreset. Monitor continues until +04:00CET/03:00UTC, script67325/PID387861; note plannedrestartgap separate fromcrash. +Currentconsole/tmp/vcore-flight-regions-group-test-start-20261030.log; afterrestart +use new uniqueconsole filename and adjust monitor console tracking if needed. +Server.log/navigation/DBErrors monitoring survives truncation automatically. +RotationPercent0 stillmustrestore15 at04:00. Otherobservation instructions below. + +# RUNNING OBSERVATION: do not finish before04:00CET Oct30 (03:00UTC) + +Commit373818628d contains all requested feature changes. Latest flight-region +binary installed, final server387859 in tmuxvcore-worldserver, freshready10s, +ports8085/8087 good. Console/tmp/vcore-flight-regions-group-test-start-20261030.log. +Do NOT restart/alter gameplay during observation unless critical recovery needed. + +Group test applied successfully to92 of110bots:76instance,16raid next block; +18below15 excluded entirely. All targets validated with native eligibility after +logging in candidates as needed. Manifest/tmp/vcore-group-test-20261030/state.json +phaseapplied. Current02:00–03:00groupformation atpoi_guard_22(SW)/poi_guard_179(Org), +next03:00–04:00mixed valid native modes. Offlinecapitalrelocation plus stalevisit, +ghost,corpse,handoff cleanup applied; other22day slots preserved. Loader restored +Enabled1; RotationPercent deliberately0 through observation (original15). + +MONITOR ACTIVE: Python/tmp/vcore-observe-groups.py, execsession67325. Writes every +20s to/tmp/vcore-group-observation-20261030/state.json and minute progress to +/tmp/vcore-group-observation-console.log. Deadline04:00Europe/Berlin=03:00UTC. +At deadline it automatically restores onlyRotationPercent to original15, reloads +config/population, writes final.json and exits. First processmissing alert was +initial spawn race before server started, NOT a mid-test crash. Script snapshot +loops capture server PID/RSS/CPU, native event counters, errors, groups/membership, +visits and handoffs every120s; saveall every300s for positions. Raw backups include +worldserver.conf.before containingcredentials, NEVER print/copy it into repo. + +Next: check monitor state/logs periodically, investigate anomalies read-only, +recover testserver only if genuinely down. Keep turn active until04:00then +self-contained report withcounts,commit373818628d, findings andunverifiedparts. +Copy safe evidence +write report/checkpoint thenlocaldoccommit if useful; no push. +Current feature git tree was clean aftercommit; thisresumeupdate isintentional. +All builds must remain-j10. No pending build/install/test prep operations. + # ACTIVE USER REQUEST: commit flight-region extension, repeat groups, observe until04:00CET Current dateOct30; user requires flight not only Northrend but also Outland and diff --git a/doc/clientless/group-departure-and-instance-modes.md b/doc/clientless/group-departure-and-instance-modes.md index e37b0837be..8caa7e32f4 100644 --- a/doc/clientless/group-departure-and-instance-modes.md +++ b/doc/clientless/group-departure-and-instance-modes.md @@ -57,3 +57,15 @@ rebuilt with -j1 to limit memory while it runs. Installed binary remains unchang Final build succeeded Oct30 01:45:11. All67 AdventureBot tests passed; the last intent-state, departure and native-DBC tests were rechecked after the final change. No installation, migration application or restart was performed. + +## Observation regression: preserve travel fallbacks + +The Oct30 live group test exposed that an active early-departure snapshot was +being reapplied on every maintenance tick after a failed journey. It overrode the +normal fallback and repeatedly regenerated the original instance plan. Fix: +apply the copied slot while still in formation; after transition, effective +WantedIntent/WantedLocation own navigation. Group plans and followers inherit +that effective fallback, and a kick retains it. The logical schedule signature +and original next day slot remain unchanged. Added regression executes repeated +maintenance, fallback inheritance and leaving the group. Departure, group-plan +and intent-state tests pass; complete -j10 build passes. diff --git a/src/server/game/World/AdventureBehaviorMgr.cpp b/src/server/game/World/AdventureBehaviorMgr.cpp index 717c8e8dfb..bf38ceec75 100644 --- a/src/server/game/World/AdventureBehaviorMgr.cpp +++ b/src/server/game/World/AdventureBehaviorMgr.cpp @@ -2178,7 +2178,10 @@ bool AdventureBehaviorMgr::UpdateDeparture(Player* player,Record& r,time_t now) } if(!r.Departure.Departed(now)) {r.Deadline=r.Departure.At;return false;} - if(r.WantedIntent!=r.Departure.Intent || r.WantedLocation!=r.Departure.Location) + // Apply the copied slot once on departure. Afterwards normal navigation + // fallbacks own the effective destination; do not pin them back every tick. + if((r.Intent.empty() || r.Intent=="groupformation") && + (r.WantedIntent!=r.Departure.Intent || r.WantedLocation!=r.Departure.Location)) { SetWanted(player,r,r.Departure.Intent,r.Departure.Location,r.Departure.ActivityEnd); TC_LOG_INFO("server.adventurebot","GROUP_EARLY_DEPART guid=%u intent='%s' goal='%s'", @@ -2204,7 +2207,12 @@ AdventureGroupPlan AdventureBehaviorMgr::GroupPlan(Player* player) if(r.Departure.Active(now)) { if(r.Departure.Departed(now)) - {plan.Intent=r.Departure.Intent;plan.Location=r.Departure.Location;plan.Deadline=r.Departure.ActivityEnd;} + { + bool applied=!r.WantedIntent.empty() && r.WantedIntent!="groupformation"; + plan.Intent=applied?r.WantedIntent:r.Departure.Intent; + plan.Location=applied?r.WantedLocation:r.Departure.Location; + plan.Deadline=applied?r.Deadline:r.Departure.ActivityEnd; + } else {plan.Deadline=r.Departure.At;plan.NextIntent=r.Departure.Intent;plan.NextLocation=r.Departure.Location;} } if(r.Schedule && local.tm_hour<23) @@ -2235,9 +2243,11 @@ bool AdventureBehaviorMgr::AdoptGroup(Player* player,Player* leader) } if(r.Instance.Active && r.Instance.Stage!=AdventureInstancePolicy::Phase::Travel)return true; auto now=GameTime::GetGameTime(); - auto const& intent=source.Departure.Departed(now)?source.Departure.Intent:source.Intent; - auto const& location=source.Departure.Departed(now)?source.Departure.Location:source.Location; - auto deadline=source.Departure.Departed(now)?source.Departure.ActivityEnd:source.Deadline; + bool early=source.Departure.Departed(now); + bool applied=early && !source.WantedIntent.empty() && source.WantedIntent!="groupformation"; + auto const& intent=early?(applied?source.WantedIntent:source.Departure.Intent):source.Intent; + auto const& location=early?(applied?source.WantedLocation:source.Departure.Location):source.Location; + auto deadline=early && !applied?source.Departure.ActivityEnd:source.Deadline; if(r.WantedIntent!=intent || r.WantedLocation!=location) SetWanted(player,r,intent,location,deadline); else r.Deadline=deadline; @@ -2250,7 +2260,12 @@ void AdventureBehaviorMgr::ResumePersonalPlan(Player* player) auto& r=it->second;if(!r.GroupOverride)return;r.GroupOverride=false; auto now=GameTime::GetGameTime(); if(r.Departure.Departed(now)) - SetWanted(player,r,r.Departure.Intent,r.Departure.Location,r.Departure.ActivityEnd); + { + // Leaving a group must neither revert to formation nor undo an already + // selected travel fallback within the copied activity block. + if(r.Intent.empty() || r.Intent=="groupformation") + SetWanted(player,r,r.Departure.Intent,r.Departure.Location,r.Departure.ActivityEnd); + } else if(r.Schedule) { auto local=Local(now);if(r.Date!=DateOf(local))Generate(player,r,DateOf(local)); diff --git a/tests/clientless/test_adventure_group_departure.py b/tests/clientless/test_adventure_group_departure.py index 702c05ff9a..9f9f5d74a4 100644 --- a/tests/clientless/test_adventure_group_departure.py +++ b/tests/clientless/test_adventure_group_departure.py @@ -79,6 +79,15 @@ int main(){setenv("TZ","UTC",1);tzset();GameTime::now=Clock(14,20);AdventureBeha // Kick/incomplete group cannot roll the copied current slot back. b.GroupOverride=true;mgr.ResumePersonalPlan(&member);assert(!b.GroupOverride&&b.WantedLocation=="deadmines_d1"); assert(mgr.InteractionSchedule(&member)=="instance:deadmines_d1"); + // A failed journey selects a normal fallback. Repeated maintenance must not + // repin it, followers inherit it and a kick retains it in the same intent. + b.Intent="instance";b.Location=b.WantedLocation="fallback_dungeon";unsigned changed=mgr.changes; + assert(mgr.UpdateDeparture(&member,b,GameTime::now));assert(mgr.changes==changed&&b.WantedLocation=="fallback_dungeon"); + assert(mgr.GroupPlan(&member).Location=="fallback_dungeon"); + b.GroupOverride=true;mgr.ResumePersonalPlan(&member);assert(b.WantedLocation=="fallback_dungeon"&&mgr.changes==changed); + a.Intent="instance";a.WantedIntent="instance";a.Location=a.WantedLocation="leader_fallback";a.Deadline=Clock(16); + mgr.AdoptGroup(&member,&leader);assert(b.WantedLocation=="leader_fallback"); + assert(b.Plan[15].Location=="shadowfang_d1"); // Restore independently of any surviving group and continue the same current slot. AdventureBehaviorMgr restored;auto&c=restored._records[2];Prepare(c,"shadowfang_d1"); restored.RestoreDeparture(&member,c);assert(c.Departure.At==Clock(14,25));