Fix flight departure recovery and Wintergrasp mount permissions

Keep takeoff clearance until actual ascent, blacklist rejected dynamic bridges, and diagnose group ground-path rejection. Synchronize native Wintergrasp client mount permission with battle state and fix duplicate Zangarmarsh graveyard ownership. Add regression tests and generic testbot aura inspection.
This commit is contained in:
Nico committed 2026-11-03 18:56:16 +01:00
1 parent fe03ea8ca5
commit a6572242c6
22 files changed
+1159 -10

No files matched your search

+864
View File
@@ -1,3 +1,867 @@
# 2026-11-03 – Automatische Tausendwinter-Clientfreigabe abgeschlossen
Der Nutzer bestätigte: Allitester kann den Zwielichtboten mit Aura 91262 nutzen.
Die Freigabe wird jetzt automatisch über den direkten AddAura-Pfad gesetzt,
wenn Tausendwinter außerhalb einer aktiven Schlacht betreten wird. Sie wird
beim Verlassen oder Schlachtbeginn entfernt und nach Schlachtende neu vergeben.
Fremde Mount-Einschränkungen ohne Flugfreigabe werden nicht übergangen.
Gemeinsame serverseitige Mount-/Zauber-/Planerprüfung bleibt erhalten.
Gezielte Tests ClientPermission, WGFlight und MountCast bestanden. Der echte
Live-Test wg_auto_verified_1829 bestand alle drei expliziten Prüfungen:
1. Aura 91262 nach Gebietswechsel automatisch vorhanden.
2. Nach Entfernen aller alten Mount-Auren Zwielichtbote 107844 frisch über
CMSG_CAST_SPELL beschworen; dessen Aura ausdrücklich vorhanden.
3. Nach Verlassen Tausendwinters Aura 91262 nicht mehr vorhanden.
Testcharakter Morvath 150 wurde anschließend automatisch ausgeloggt.
Testbot-API dafür generisch um has_aura/remove_aura ergänzt, ohne Botprofile
oder AdventureBot-Steuerung als Abhängigkeit einzuführen.
Build -j10 und Installation erfolgreich. Der erste Restart dieser Aufgabe
hatte noch den separaten GameObject::RemoveFromWorld/ZoneScript-Absturz;
Core worldserver-20261103-180256.core und passendes worldserver-before-fix
im Checkpoint sind erhalten. Beim ergänzenden Build war der Loader weiterhin
pausiert, SafeLogout erneut angefordert und null Sessions nachgewiesen.
Der anschließende Shutdown von PID68290 endete NORMAL. Kein weiterer Core.
Matching Binary worldserver-before-direct-aura ist gesichert.
Finaler Server PID71783: frische ready-Meldung, Ports 8085/8087 und Fortbestand
bestätigt. 118 Adventure-Bots online, Loader wieder 1, SafeLogout pending 0.
Restbots vor dem ersten Shutdown mit GUID/Fraktion/Position/Flags gesichert.
Recovery nach Wiederanlauf: Gargar93 und Volakmar128 hingen ohne Flugzustand
über dem Boden; beide nativ nach Orgrimmar teleportiert, Ergebnis geprüft.
Andere normale Taxi-/Transportzustände unverändert. Allitester nicht manuell
teleportiert oder verändert; Clientfreigabe wird nun automatisch verwaltet.
Artefakte: checkpoints/2026-11-03-wg-client-permission/ (Live-Ergebnis,
Testskript, Build/Install/Startup, Roster, Recovery und result-final.json).
Große Artefakte bleiben lokal per .git/info/exclude von der UI-Erfassung
getrennt; keine großen Git-RAM-Jobs mehr beobachtet. Keine Dateien gelöscht,
keine Commits/Pushes. Alle früheren Source-WIP sind erhalten.
Die erneute visuelle Abnahme mit Allitester steht noch aus. Der separate
ZoneScript-Lebensdauerfehler beim Shutdown ist noch nicht behoben.
---
# WG-Clientpermission Nachprüfung/zweiterBuild läuft
ErsterClientpermissionBuild/Install erfolgreich, PID68290 ready+Ports bestätigt.
Loader weiterhin0, AdventureBotsnochNICHTwiederhergestellt,Online0.
ErsterLiveTest nurmounted/canFly,DBAuraSaveKeinNachweis(kein91262 gespeichert),
vorhandeneMountAura32243machtaltenTestnichtaussagekräftigfürfrischen107844.
DaherVergabe vonCastSpell aufAddAura umgestellt (direkterGM-AuraPfad).
TestbotAPIgenerisch umhas_aura/remove_aura erweitert, um echteaktiveAuren zu
prüfen stattvorhandeneMountsfehlzuinterpretieren. NeuesScript
automatic_permission_verified.lua:Altmounts+91262entfernen,WGbetreten,
HasAura91262prüfen,nativeRequest107844,HasAura107844prüfen,Orgrimmar,
HasAura91262mussfehlen. DreiChecksimResult verpflichtend!
VorZweitbuildpopulationreload+safeLogoutall erneutangefordert,Online0;Build-j10
läuft(build-direct-aura.log),Install/RestartnochOFFEN. Keineerneute5minnötig,
weilkeineSessions. AktuellenMatchingBinaryvorInstallalsworldserver-before-direct-
aura sichern. BisherigerShutdown182? wiederGameObject::RemoveFromWorld651
m_zoneScript->OnGameObjectRemove,Core180256+Matchingworldserver-before-fixim
client-permissionCheckpoint gesichert. OffenerZonenScriptLebensdauerbug.
AllealtenSourceWIP erhalten. LoaderamEndewieder1+vorherige118Botwiederherstellen.
---
# WG-Clientfreigabe nach bestätigtem Allitester-Auratest in Arbeit
Nutzer bestätigt .aura91262=>Zwielichtbotegeht. AutomatischeSynchronization nun
BattlefieldMgr::UpdateWintergraspFlight(Player*/Map*): setzt91262beiWG-Frieden,
entferntbeiVerlassen/Schlachtbeginn; OnBattleStart/End refreshtSpielerimGebiet,
Player::UpdateArea refreshtbeimGebietswechsel. Fremde336-AurenohneFlug2werden
nichtübergangen. BestehendeServermount/SpellInfo/Planner-Ausnahmenbleiben.
Tests ClientPermission/WGFlight/MountCast PASS. Testbot150hatvorher KEINE
91262incharacter_aura, ermöglichtNachweisautomatischerVergabe nachRestart.
Build-j10läuft. Loader1->0+reload+SafeLogoutlautoperation.json, volle5min-Regel;
Artefakte checkpoints/2026-11-03-wg-client-permission/. Installation/Restart/
Recovery/LoaderRestore+automatischeAura-Liveprüfung noch ausstehend.
Gitgroßartefakteweiterlokalausgeschlossen,keineGitRAMjobs. AlleanderenWIPerhalten.
---
# Allitester21: GoldenerGreifgeht, Zwielichtbote107844nicht
Nutzerkorrektur: GoldenerGreif nutzbar, Zwielichtbote MeldungIhrkönntdashiernicht
verwenden. Allitester21 lvl85 map571zone4197 pos4503.28/1941.55/435.29,
Riding375/375,54197+90265+90267aktiv,107844gelernt. DBgespeicherteAura2458,
keineMountRestriction-Aura. Native Testbot150lvl80/riding375/54197/107844:
CMSG_CAST_SPELL amBodenWG erfolgreich mounted1/canFly1. Testscript autoLogout,
Ergebnis twilight-harbinger-native-test.json. Somit serverseitiger Aufruf beider
Mounts erlaubt, Client-Freigabe weiter unvollständig. DBCMountType107844=238,
GoldenerGreif32235=248. AreaMountFlags13imClient fehlenweiterFlug2.
Client-Freigabe-Aura91262 Wintergrasp-InactiveEnableFlyingMounts hat336/misc15,
91285ActiveEnableFlyingMounts ebenfalls15,86973PermittedFlightArea15.
Keine dieserAuren aktuellinspell_area. AsynchroneDiagnosefrageanNutzer:
Allitester SELBST anwählen,.aura91262,Zwielichtbotetesten;entfernbar.unaura91262.
AntwortnochAUSSTEHEND. Keine neue Source-/DBänderung für diese Nachdiagnose,
kein weitererBuild/Restart. UsernachweisdesClienttests vor3.Korrekturabwarten.
Wennbestätigt: ClientFreigabe an friedensabhängigeWG-Regel koppeln, bei
Schlachtbeginn sicherentfernen,beimVerlassenauch. ServerseitigeAura-Priorität
in Unit/SpellInfo beachten,damit91262währendBattlekeinFluglochöffnet.
---
# WG-Mountcast und Git-Speicher korrigiert, 03.11.2026
SpellInfo::CheckLocation ONLY_FLYING_AREAS verwendet jetzt ebenfallsWG-Regel;
expliziteMountRestriction-Auren weiter vorrangig. Test_wintergrasp_mount_cast
mitextrahiertemProduktionsblock PASS. Build-j10/Install PASS. SafeLogout17:56:10,
volle5min,15Restbots+Flags/Positionssnapshotgesichert. Shutdown andererCrash:
Creature::RemoveFromWorld329 GetZoneScript()->OnCreatureRemove(this), Core
worldserver-20261103-174952.core+Backtrace, matchingworldserver-before-fix
imwg-mount-castCheckpoint. ZM-DoubleDelete nichtimneuenStack. Nochzuuntersuchen.
NeuerServer PID61228 ready+Ports8085/8087 bestätigt. 118erRoster wiederhergestellt,
Loader1,pending0. Suspendierte160/176/186 nachRestart Fraktionshauptstadt,
Positionen nativ bestätigt,160fliegtanschließendnormal. KeineanderenTransport-
Übergängeunterbrochen. Testbot150MorvathLevel80/riding225/coldweather/32243
amBodenWG(4059.27,2747.79,354.88): RequestCast=nativesCMSG_CAST_SPELL,
nativeProbe mounted1/canFly1/falling0. Scriptpassed,autoLogoutabgeschlossen.
Kopielive-test.json+native-evidence.log imCheckpoint. EchterSpieler-Abnahmeoffen.
Git-RAM:UItemporaryIndexgitadd verarbeitete1.1GBbackups. GroßeDiagnosedateien
lokal.git/info/exclude,keinDateiverlust/keinnormalerGitIndexeingriff. ZweiUIjobs
nachenv/cwdPrüfungbeendet,keineweiterengitProzesse danach,RAMentlastet.
NeuegroßeArtefakteweiterlokalausschließen! KeinCommit/Push dieserWIP.
---
# 03.11.2026 weiterer WG-Mountpfad und UI-Git-RAM in Arbeit
Nutzer meldet Einfluggeht, Aufsitzennicht+mehrere1GB-Gitprozesse.
Übersehener SpellInfo::CheckLocation ONLY_FLYING_AREAS-Pfad liestMountFlagsdirekt.
Jetzt ebenfalls gemeinsameWG-Regel eingebunden, expliziteAuraMountRestriktionen
bleiben vorrangig. Produktionsextrakt-Test test_wintergrasp_mount_cast.py PASS
fürHaupt/Untergebiet/Frieden/Schlacht/Ende/anderesGebiet/Auravorrang.
Build-j10läuft. Loader1->0+reload+SafeLogout17:56:10+01, volle5min-Regel.
Artefakte checkpoints/2026-11-03-wg-mount-cast/. Install/Restart/Recoveryoffen.
Gitprozesse sind CodexUI-diff gitadd mit GIT_INDEX_FILE=/tmp/.../index.
Mehrere1.1GBServerbackups +100MBLogs lagenuntrackedimRepo=>UIhashtealles.
Große>10MBArtefakte individuell inlokaler.git/info/exclude ausgeschlossen,
auchZukunftsmusterworldserver-before-*. KeineDateigelöscht/keinrealerIndexgeändert.
Zwei laufendeUIgitadd58568/58654 nachPrüfungcwd+tempindex perSIGTERMbeendet,
keineweiterengitProzesse danach. Vorher mehrereGBRAM, Swapvoll; nunentlastet.
AlleSourceWIPerhalten; keinCommit/Push.
---
# Tausendwinter-Flugkorrektur installiert und nativ geprüft
Gemeinsame BattlefieldMgr-Regel in Unit-Mountprüfung und ClientlessFlight-Estimate.
Frieden/disabled/fehlend erlaubt WG+Untergebiete, aktive Schlacht gesperrt;
explizite MountRestriction-Auren bleiben unangetastet. Tests WG/FlightPolicy/
TakeoffHandoff/FreeFlight PASS, Build-j10 und Install PASS.
Wichtig: Während Build um17:46:55 Kernel-OOM-Kill PID54176 (journalgesichert),
KEIN normaler Shutdown/keinCore; gestartetes SafeLogout17:46:15 hatte bis Kill
nahezu alle ausgeloggt, DBRest42+169 gesichert. Loader blieb0 bis frischemStart.
Keine forcierte Einzelabmeldung, keine Binaryinstallation am laufendenProzess.
Nach erfolgreichemBuild frischerGDBStart PID57089, ready+Ports8085/8087 bestätigt,
118Bots wiederonline, Loader1/population reload,pending0. Kernel-OOM-Evidenz
checkpoints/2026-11-03-wg-flight/kernel-oom.log. -j10 weiterhin Nutzerregel,
Parallelbuild mit11GiRAM/vollemSwap hat hier OOM ausgelöst, nicht Codecrash.
Nativ35Karggan/162Aruendas/176Ashaelri an ORIGINALEN WGPositionen nachLogin:
alle mounted1/canFly1/falling0, keineTeleportation dieser3. VolleReisefortsetzung
noch nichtverifiziert. OOMRest42geerdet,169Bromdan suspendiertohneFlugzustand:
RecoveryStormwind, Position+anschließend regulär flying1 bestätigt.
Testartefakte/Operation/Roster/NativeEvidence/result.json imwg-flightCheckpoint.
KeineCommits/Push, alle bisherigen anderenWIPbewahrt. User-Spielabnahme offen.
---
# 2026-11-03 Tausendwinter-Flugkorrektur in Arbeit
Nutzer beauftragt Fix. Gemeinsame BattlefieldMgr::IsWintergraspFlightAllowed
prüft map571+DBCManager::IsInArea(4197), erlaubt bei fehlendem/deaktiviertem
Battlefield oder Frieden, verbietet aktive Schlacht. Unit::GetMountCapability
ergänzt Flugflag nur im normalen Gebietspfad, explizite MountRestriction-Auren
bleiben vorrangig. ClientlessFlightMgr::Estimate nutzt dieselbe Regel auch für
Untergebiete und lehnt aktive Schlacht ab. Keine DBC-/DB-Änderung.
Test_wintergrasp_flight.py und FlightPolicy PASS, Abflug-Handoff PASS.
Loader1->0,population reload,safe logout all17:46:15+01; Build-j10 läuft,
volle5min bis Shutdown bei Restbots. Roster/Operation/Logs:
checkpoints/2026-11-03-wg-flight/. Install/Restart/Recovery/Restore ausstehend.
Alle anderen WIP erhalten. Nicht committen/pushen ohne Nutzerauftrag.
---
# Tausendwinter: permanentes Flugverbot im Gebietspfad identifiziert
Nutzer selbst beim Einfliegen abgemountet, Bots35/162/176 suspendiert.
Konfig Wintergrasp.Enable0; BattlefieldMgr::GetBattlefieldToZoneId ignoriert
Disabled, Update ignoriertDisabled, daher kein Beleg laufender Schlacht.
Statische enUS AreaTable.dbc:4197 UND alle Untergebiete MountFlags13(0x0D),
AllowFlyingMounts0x02 FEHLT durchgehend. Unit::GetMountCapability nutzt diese
Flags ohne wartimeabhängige WG-Ausnahme (außer allgemeinen MountRestriction-Auren),
Player::UpdateArea ruft UpdateMountCapability, dadurch Flugfähigkeitverlust bei
Zoneneintritt unabhängig von Battlefield-IsEnabled/IsWarTime möglich.
ClientlessFlightMgr nutzt ebenfalls statische AreaMountFlags zur Planung.
Navlog bestätigt17617:10:24/16217:20:06 flight permission lost or total timeout,
map571 Z397.55/Z385.85 an vomNutzer beobachteter Stelle.
91604-SpellArea selbst ist durch Enabled/WarTime geschützt; alleinige Änderung
CanFlyIn wäre keine Lösung. Nächster Fix muss gemeinsame Mountfähigkeitsprüfung
und Botplaner mit identischer tatsächlicher WG-Freiflugregel versorgen, reguläres
Wartimeverbot erhalten. Keine Änderung/Build/Teleport für diese Diagnose.
---
# ZM-Ownershipkorrektur abgeschlossen, 03.11.2026
ASan100Zyklen PASS, alte Variante heap-use-after-free reproduziert; Build-j10 und
Install PASS. SafeLogout17:20:08, volle5min eingehalten; verbleibende21 mit
GUID/Fraktion/Position/Diagnosen gesichert. Alter Server beim Shutdown erneut
bekannter Crash, Core164154+passendes Binary im zm-ownershipCheckpoint gesichert.
Neuer Server PID54176, frische ready-Meldung,Ports8085/8087 und Fortbestand
bestätigt. Vorherigen118erRoster wieder eingeloggt, Loader1 wiederhergestellt,
safe logout pending0. Recovery bei suspendierten Bots ohne Flugzustand:
73/92/112/118/161/163/164/165/167/186 nativ Fraktionshauptstadt teleportiert,
Positionen nachher bestätigt;118/164 fliegen anschließend wieder regulär,
keine Fallbewegung. Übrige reguläre Taxi-/Transportzustände erhalten.
Gezielter ASan-Abbautest verifiziert Fix; vollständiger Shutdown der neuen
Version noch nicht durchgeführt. Keine weiteren Build-/Neustartschleifen nötig.
Kein Commit/Push beauftragt. Alle bisherigen anderen WIP erhalten.
Artefakte checkpoints/2026-11-03-zm-ownership/; Regression
tests/clientless/test_zm_graveyard_ownership.py.
---
# 2026-11-03 ZM-Ownershipkorrektur in Arbeit
Nutzer beauftragt Fix. m_Graveyard nun nichtbesitzender initialisierter Zeiger;
AddCapturePoint übernimmt einziges Eigentum. Regression extrahiert echte
Member-/Setup-/AddCapturePoint-Implementierung: ASan100Zyklen PASS, alte Variante
ASan heap-use-after-free reproduziert. Build-j10 läuft. Loader1->0+population
reload+safe logout all um17:20:08+01 angefordert; volle5min-Regel. Roster/Logs
checkpoints/2026-11-03-zm-ownership/. Installation/Restart/Recovery/Loaderrestore
noch ausstehend. Alle vorhandenen anderen WIP bleiben erhalten.
---
# Shutdown-Dump untersucht: doppelte Ownership des Zangarmarschen-Friedhofs
Core144731 mit exakt gesichertem worldserver-before-fix geladen. Crash Nullcall
beim delete OPvPCapturePoint0x7ffeba24c740, Mapkey0. Stack OutdoorPvPZM-Destruktor
->OutdoorPvP-Destruktor->m_capturePoints-unique_ptr-delete. SetupOutdoorPvP
OutdoorPvPZM.cpp196/197 erzeugt m_Graveyard als unique_ptr und registriert .get()
mit AddCapturePoint. OutdoorPvP.cpp427 reset(cp) übernimmt denselben Zeiger
nochmals in einen unique_ptr. Abgeleiteter Destruktor löscht m_Graveyard zuerst,
Basisklassenmap löscht den bereits zerstörten CapturePoint erneut. Dump bestätigt
m_Graveyard=null im Basisklassenabbau, m_TypeId4, CapturePointmapkey0, Nullcall.
Rootcause doppelte Ownership, unabhängig von AdventureBot-Navigation. Zonenladen
kann Instanziierung herbeiführen; zum Fehler reicht anschließender Objektabbau.
Korrektur: ausschließlich CapturePointmap besitzt Objekt; ZM m_Graveyard als
nichtbesitzender Verweis. Noch nicht implementiert, nur Diagnose beauftragt.
Gezielte GDB-Ausgabe checkpoints/2026-11-03-shutdown-analysis/gdb.txt.
Kein Build/Restart/Änderung am laufenden Server.
---
Abschluss: PID51247 bleibt aktiv,118 Bots online,Loader1/pending0.
Recovery102+159 nativ in Sturmwind(-8833.07,622.778,93.932),keineFallbewegung
verifiziert. Build/Tests bestanden wie dokumentiert, Spielabnahme bleibt offen.
# 2026-11-03 Korrekturen installiert
Abflug/verspätete Bridge-Sperre implementiert, gezielte Regressionen PASS,
Build-j10/Install erfolgreich. SafeLogout16:35:11, nach voller5min Rest19
mit DBRoster und nativen info/flight-probe/transport-Ausgaben protokolliert.
Shutdown erneut bekannter separater Destruktorcrash: Core144731+Backtrace,
passendes altes Binary im takeoff-recovery-Checkpoint gesichert.
Neustart PID51247, frische ready-Meldung+Ports8085/8087+Prozess bestätigt.
119erRoster nativ wieder eingeloggt; zunächst Hallan158 fehlend, Login nachgeholt.
Loader wieder1, native population reload, safe logout pending0.
Restbots nachLogin geprüft. Renren159 und Corren102 ohne aktiven Flug,
aber über Boden suspendiert: Recoveryteleport Hauptstadt Sturmwind ausgeführt.
Corren versehentlich zuerst Orgrimmar angefordert, sofort nach Sturmwind korrigiert.
Andere laufende Flüge/Taxirecovery nicht abgebrochen. Abschließende Verifikation
noch ausstehend. Keine Commits/Push in dieser Aufgabe. Spielabnahme offen.
---
# 2026-11-03 Abflug- und Recoverykorrektur in Arbeit
Nutzer beauftragt beide Korrekturen. ClientlessFlightPath setzt Departed nicht
mehr bei Segmentausgabe, sondern beim folgenden Planen anhand tatsächlicher
Bodenfreiheit >=Safety. Geprüfte Departure-Korridore/Vertikalfallback gelten
bis dahin weiter. RecoverTravel sperrt verspätet abgelehnte dynamische
local_bridge-Kanten mit from->to auch bei route-local-PathRejected.
Neue Regressionen test_flight_takeoff_handoff.py und test_dynamic_bridge_recovery.py
PASS. Free-flight, elevated, handoff, shared/group flight, policy, planner,
group-travel, ground-exit und recovery-policy PASS. Unveränderter bestehender
Abflugtest test_flight_departure.py scheitert mit unordered_map::at in seinem
Testdouble; ClientlessFlightMgr.cpp wurde in dieser Aufgabe nicht verändert.
Loader1->0, population reload, safe logout all um16:35:11+01:00 angefordert.
Build-j10 läuft; keine erneute 60s-Ausnahme: volle 5min vor Shutdown bei Restbots.
Operation/119erRoster/Buildlog: checkpoints/2026-11-03-takeoff-recovery/.
Installation/Restart/Recovery/Loaderwiederherstellung noch ausstehend.
---
# Erster Abflug: Diagnose und ausdrücklich gemerkter Recovery-Punkt
Nutzer stimmt dem Recovery-Befund zu und verlangt, ihn zu merken: verspätete
PathRejected-Fehler dynamischer local_bridge-Kanten (DbId0) müssen die konkrete
Verbindung für die Reise sperren, damit Recovery Alternativen sucht. Als offener,
abgestimmter Folgepunkt festgehalten; noch KEINE Implementierung beauftragt.
Erster Abflug 03.11.2026 14:28:59, Ashaelri176: erster Segmentendpunkt
(-8811.23,607.63,109.21), Abbruch bereits bei(-8826.7,622.306,96.4122).
ClientlessFlightPath::Next setzt Memory.Departed=true bereits bei AUSGABE des
ersten Segments. Update plant bei <=1500ms Restlaufzeit schon währenddessen
weiter. Folgende Next-Aufrufe behandeln den noch bodennahen Bot als Reiseflug:
Corridor prüft auch i=0 und fordert Safety8.0. Read-only native flight probe mit
Renren159/map0 an exakt der historischen XY-Position liefert ground94.314,
ceiling550.000. Somit Z+0.5=96.9122 < ground+8=102.314: JEDER normale Kandidat
scheitert bereits an seinem Startpunkt. Departure-only Vertikal-Fallback ist
wegen Departed=true ebenfalls aus. Kein Beleg für ein unpassierbares Hindernis
als Ursache dieses Abbruchs: der erste Korridor war zuvor freigegeben worden.
Beleg first-departure-analysis.json und native Probe im startup.log unter
2026-11-03-ground-validator. Probe176 war auf map530 unbrauchbar; nur Probe159
auf map0 für die Rechnung verwendet. Bots dabei nicht bewegt/umgeplant.
Korrekturvorschlag: Abhebezustand bis tatsächlich ausreichender Bodenfreiheit
beibehalten, anschließende Korridore weiter mit geprüfter Abflugfreiheit planen;
Handoff während Abheben konsistent behandeln. Keine Sourceänderung/Build/Restart.
---
# Greifenmeisterroute rekonstruiert (keine neuen Sourceänderungen)
NutzerfragtwarumTaxi2/warumkeinGreif/warumgleicheRetries. RotiertesNavlog
adventurebot-navigation.log.2026-11-03_15-10-07 enthältOriginalablauf.
14:28:49Rose->Tradecenter;14:28:58FreiflugzumPortalGOspawn200627,
DBentry207694PortaltoTwilightHighlands(-8186.15/413.729/116.75).
14:28:59keinbegrenztersichererFlugkorridor,14:29:00sicherzurückTradecenter.
RecoverywähltTaxi2ALSSTARTANKER,läuftdorthin(19sec),nächsteKanteist
weiterhinfree_flightzumPortal,nichtTaxi. DortAbflugpunktsucheliefert106.2yd
Bodenweg64ydSuchradius,derownerValidatorunterbricht. NächsteRecoveryroute
Taxi2->Tradecenterlocal_bridge(Id0) scheitert5malwiebekannt.
GenauerRetrybug: StartTravelgibt trotzsofortStatusPathRejectedtruezurück,
daherlocal_bridgeStartzweigmitFailedBridgeKeys.insert(from->to)wirdübersprungen.
SpäterallgemeinerUpdateMoving-Zweigmeldetroute-local-PathRejected/DbId0;
RecoverTravelblockiertnurDBIds!=0. SonderblockfürStartankerbetrifftnurRouteStep0,
hierStep1=>keineSperre. ReiseKostenprofil/JitterbleibtproReisefest(gewollt),also
bleibtungesperrteBrückebesteRoute. KeineTaxi-Fahrtangefordert/fehlgeschlagen.
NumerischenhistorischenKostenvergleichPortalvsGreifnichtbehaupten; Logbelegt
gewähltePortalroute,keinegespeichertenAlternativkosten. Artefakteoriginal-route.log,
route-before-stuck.log,original-route-explanation.jsonimground-validatorCheckpoint.
NurRead-onlyAuswertung+Checkpoint,keinweitererBuild/Teleport/Reset.
---
# Gruppensicherheitsdiagnose abgeschlossen: konkrete LOS-Kollision
NeuesteAufgabe: Nutzer verlangt genauenAblehnungsgrund fürAshaelri176/Corric166/
Taliaarnora164 amSWGreifenmeister. MangelsDetaildiagBuildangefragt; Nutzer
explizitJA+einmaligeFrist60s statt300s (nurfürdiesenDiagBuild!).
19ZeilenWARN-DiagnoseinAdventureGroupTravelMgr.cpp plusTestmacro ergänzt;
keineBewegungs-/Sicherheits-/Planungsregelngeändert. Test_adventure_group_travel
undBuild-j10PASS,InstallPASS. Loaderpausiert+SafeLogoutall vorBuild14:41:37,
22Restbots+verfügbareFlagsgesichert, erstnach>202snormalShutdown10. Kein
EinzelForceLogout/FlightAbort. WiederShutdownNULLcall,Core121738+passendesELF
worldserver-before-diagnosticsgesichert. Standard5MinfürkünftigeBuildsbeibehalten.
Befundnativerstfüralle3gleich: LOSsegment9von(-8856.588,517.633,109.881)
nach(-8858.637,521.069,109.340) scheitert. VorigeBodensamplesbestanden.
OfflineRay-Triangle-NachrechnungmitechtenVMAPDateien reproduziertTrefferin
Sw_Tradedistrict.wmo spawn46365,group13/id27435,Tri37+43,erstTreffer
(-8856.671,517.772,109.859). Zwei senkrechteFlächenaneinerModellecke;
welchersichtbareBauteilunbekannt. NahesFass46585nichtgetroffen.
Daher ursprünglicheBlockadekonkreteSichtlinienkollision,keinMaxSlope-/Height-
Schwellwertfehler. SpätereErsatzpfadehabenandereBoden/LOSAblehnungen.
KompletterMMAPPfadenthältgeradenTeilstreckenstrahl,derechteVMAPgeometrie
schneidet. RecoverywähltdieselbeID0local_bridge=>5fachExhausted.
NochKEINNavigationsfixvorgenommen; sinnvolleKorrekturwäregeometriesichere
lokaleUmgehung/Stützpunktwahl+RecoveryfürsynthetischeBrücken,keinblindes
LockernvonPrüfungen. Artefakte checkpoints/2026-11-03-ground-validator/README.md,
result.json,confirmed-rejections.log,check_los_mesh.py,los-triangle-hits.json.
Server40815/GDB40804ready/Ports/Coreunlimited.119vorherigeBotsrestauriert,
Loader1/Pending0/native119online.22Restzuständegeprüft;42/99/118ausgescheiterter
HängefluglageinHauptstadtgeborgenundPositionsfortschrittgeprüft. DreiRaidbots
176/166/164NICHTteleportiert,zurDiagnoseanOriginalpositionangemeldet;
natürlicherPlanwechselnachRestartführtesieaufandereWege,keinenFixbehaupten.
Raidschedule15für03Novbleibtgesetzt,keineZeit-/Tagesplanänderungen;
Nutzerbeobachtetselbst,KEINVollzeitobserver. SourceDiagundTestuncommitted.
LetzterCommitfe03ea8ca5 VMAPFix unverändert,CrashBasisjetzt144731.
---
# Raidtest: dreiBotsamSWGreifenmeister blockiert, Diagnosegesichert
NutzermeldetAshaelri176/Corric166/Taliaarnora164fest. Read-onlyNativeab14:31:
alleamTaxi2(-8841.06/489.656/109.607),Gruppenleader176,group6.
LokaleBrückeTaxi2->stormwind_tradecenter (DbEdgeId0) MMAPkomplett/nichtverdächtig,
48Punkte/189.55yd/maxDeltaZ2.88; StartTravelweistOwnerGroundSafetyValidatorab.
Owner=AdventureGroupTravelMgr::ValidateGroundPath, prüftBodensamplesalle2yd
undVMAPLoS. WelcherSample/LOSgenauabgelehntwirdnochNICHTdiagnostiziert;
keinenfalschpositivenFilterbehaupten. Flugabflugvorbereitunggroundapproach
interrupted Folgefehler. FünfRecoveryReplanswählendieselbeId0Brücke,
blockedEdges0=>RecoveryExhausted. BekannteoffeneGroundSafety/RecoveryBaustelle
nunlivewiederbeobachtet,nichtdurchVMAP-LifetimeFixbehobenbehaupten.
Rohlogssowiejsonuntercheckpoints/2026-11-03-1500-raid-test/gryphon-master-*.
KeineTeleports/Reset/Sourceänderung/Build/RestartoderVollzeitbeobachtung.
NutzerbeobachtetlaufendenTestselbst,AuswertungnuraufAnforderung.
---
# NeuerZehnerRaidtest03.11.2026 eingerichtet, Nutzerbeobachtet
NutzerstartetWiederholungundverlangtKEINEVollzeitbeobachtung/automatischeAuswertung.
Gleiche10GUIDs159/160/161/162/163/164/165/166/167/176,alle85,
2Tank(167/176),2Heal(161/162),6Damage. AlleofflinezurGoldenenRoseposition
map0 -8864.73/669.015/97.9031 teleportiertundverifiziert,alle10nativangemeldet;
zusätzlichonlineStandortgesetzt,alteReiseexecutorendurchLogoutneugestartet.
NativeGruppenaltzustand2nur159/162überinteractionleavegelöst,keineSQLGroup-
Manipulation/zwangsweiseRaidzuteilung. AlteHandoff/InstanceVisitnurfürdiese10
vorhergesichertundofflinegelöscht. Tagesplänenativeditplanerst15raid/
instance_visit_at_6354_d0,dann14groupformation/the_gilded_rosegesetzt;
alle20Rowsfür20261103verifiziert. Normaler10erModus,2/2/6.
Gruppenbildensichnativ(anfangsevtTeilgruppen2/5),keinenFormationManagerrun
manuellausgelöst. NativeRebalance/FrühabreisebleibenwievorigenTestsaktiv.
TemporärerGM-Teleportwiederentfernt+Reload. LoaderwährendSetup0,amEnde1+
ConfigReload/PopulationReloadrestauriert. AnderePläne/Profileunverändert.
Checkpoint checkpoints/2026-11-03-1500-raid-test/manifest.json,verified-plans,
roster-before,offline-rose,configured-native,groups-at-setupundBackups.
KEINObserver/Timer/Evaluationjob gestartet. ErstaufNutzerwunschAuswertung.
AktuellerServer33318/passivGDB/Crashaufzeichnungbleibtaktiv,keinBuild/Restart.
---
# VMAP-Fix lokal committed: fe03ea8ca5
Auf Nutzerauftrag Commit fe03ea8ca5 auf feature/clientless-player-core erstellt:
Fix VMAP probe handle leaks and tile model ownership.
Enthält MapTree.cpp/.h und test_vmap_tile_lifetime.py. Nicht gepusht.
Installierter und geprüfter Sourcezustand entspricht dem Commit; kein zusätzlicher
Build/Restart erforderlich. Lokale Session-/Diagnose-/Coreartefakte bleiben erhalten.
---
# Abgeschlossen03.11.2026: VMAP-Crashursache korrigiert, Server wiederonline
Nutzerauftrag Serverofflineuntersuchen: Core011325von06:08:42 gesichert,
passendesELF untercheckpoints/2026-11-03-crash-0608/worldserver.crashed.
ObjektShards210760/entry138492/display1667,Arathi45/map0,
Floatingpurplecrystal01.m2; alterWorldModel-Speicher enthältSpline<int>.
Kausalkette: CanLoadMap leaked äußerenTile-FILE bei jedemProbe;
Core4075stdioStreams/4069unbenutzteReadStreams/MAXFD4095beiLimit4096.
Modellacquirekonnte wegenFDmangel scheitern; LoadMapTilezählte dennochSpawn,
UnloadMapTilegabblindModellnamenfrei undkonnte spätererworbeneGameObject-Ref
freigeben. BeideFehlerinProduktionsmethodentestsgegen6f8f59ec6dreproduziert.
FixMapTree.h/.cpp: ursprünglichenFILEprüfen+schließen; proTileLedgerder
wirklicherworbenenReferenzen, keineFreigabenfehlgeschlagenerLoads;
UnloadohneDateireopen,partial/shared/duplicate/parentfälleabgedeckt.
NeuerTest tests/clientless/test_vmap_tile_lifetime.py, --baseline6f8f59ec6d
reproduziertbeidealtenFehler; neuefd/lifetime/sharedTests PASS.
Build-j10/Install PASS. KeineBotspezifik-AbhängigkeitimCorehinzugefügt.
ServerwarbeimAuftragbereitsoffline,0liveSessions; Loader0vorBuildgesetzt,
keinBinarylaufenderProzesseüberschrieben. DanachLoader1+beideReloadsrestauriert.
NEUERServer33318unterGDB33307, ready/Ports8085+8087/Coreunlimitedverifiziert.
Native110Bots/Pools50/5/50/5/pending0/errorleer. FD-Zahlbleibt26unterBotload,
final26FDs/keineoffenenVMAPTiledateien. AlleBefunde/Testlogs/Build/Install/
FDsamplesinCheckpointREADME.md/result.json/final-status.log.
Crashaufzeichnungpassivweiteraktiv,neueBasisworldserver-20261103-121738.
Langzeitstabilitätnichtalsbewiesenmelden; Stundenreproweiterbeobachtbar.
SeparaterShutdownOPvPCapturePoint-Crashnichtgezieltkorrigiert.
SourcefixundTestuncommitted,keinPush. LetzterCommit6f8f59ec6dbetrifftFahrstühle.
---
# Crash-Fix installiert, Population wird wiederhergestellt (03.11.2026)
Neuer Test-Worldserver PID33318 unter passivem GDB, Start12:17:37 erfolgreich:
frische ready-Meldung, Ports8085/8087 und unlimitedCore bestätigt.
Loader1 mit ConfigReload+PopulationReload restauriert, Ziele50/5/50/5.
Zuletzt39Bots online, Handles bleiben26, keine dauerhaft offenen vmtile-Dateien.
Noch bis110Bots prüfen und FD-Endwert/Result.json/README aktualisieren.
Rootcause und Code: siehe checkpoints/2026-11-03-crash-0608/README.md.
MapTree.h/.cpp und neuer Test test_vmap_tile_lifetime.py uncommitted.
CanLoadMap-FILE-Leck plus unberechtigte Freigabe nach fehlgeschlagenem Modell-
Acquire reproduziert (Baseline6f8f59ec6d); korrigierter Code alle3Tests PASS.
Build-j10/Install PASS, alter Core+kompatibles ELF erhalten. Keine Pushes.
Schlussbericht muss Langzeitstabilität ausdrücklich noch offen lassen;
Stdio-Kernbefund4075/MaxFD4095, neuerServer26FDs auch nach mehreren Kartenloads.
---
# Aktuell03.11.2026: Crash06:08Ursachegefunden/behoben/Neustartläuft
Nutzer meldeteServeroffline. NeuerCore011325von06:08:42+passendesELFgesichert
untercheckpoints/2026-11-03-crash-0608/. ZUERSTdortREADME.mdlesen.
WiederstalesWorldModelinGameObjectModelDestruktion; diesmalShards210760,
map0Arathi45, ModellFloatingpurplecrystal01.m2; alteAdresseenthältSpline<int>.
ImCore4075offeneStdioStreams/4069unbenutzteReadStreams/MAXFD4095=>Limit4096.
ROOT:CanLoadMapschließtäußeresTileFILEnicht+LoadMapTilezähltauchfehlgeschlagene
ModelAcquires,UnloadTilegibtblindFilenamefrei=>kannspätergeladenesdynamisches
Modellvorzeitiglöschen. BeideFehlergegenHEAD6f8f59ec6dmitproduktionsmethoden-
Testsreproduziert. FixCanLoadMapschließtursprünglichenFILE; proTileLedgerder
wirklicherworbenenModellreferenzen,keineFreigabefehlgeschlagenerLadevorgänge,
keinDateireopenbeimUnload;Duplicate-/Partial-/Parent-/Sharedfälleabgedeckt.
NeueDateitests/clientless/test_vmap_tile_lifetime.py+MapTree.h/.cppuncommitted.
Testsfd/lifetime/sharedPASS, baselinebeideFehlerreproduziert. Build-j10/InstallPASS.
ServerwarbeimAuftragbereitsoffline,keineClientlessSessionsfürSafeLogout;
Loader0vorTests/Build/InstallgesetztundProzessabwesenheitgeprüft. KeineBinaries
laufenderServerüberschrieben. PassiveGDBneugestartet12:17:37, startup.logim
Checkpoint. NächsterSchrittReady/Ports/Corelimitprüfen,Loader1+Config/Population-
Reload+110Botsrestaurieren,FDzahlunterBotloadbeobachten(bisherLeck=>4096).
Cores/alteELFnichtlöschen. KeinFixfürseparatenShutdownCapturePointCrashbehaupten.
---
# Lokal committed: Fahrstuhlfix 6f8f59ec6d
Auf Nutzerauftrag lokal auf feature/clientless-player-core committed:
6f8f59ec6d Fix short-stop elevator travel and recover stranded passengers.
Enthält3TransportSourcefiles,2Regressionstests,FahrstuhlanleitungundTransportdoku.
KeinPush. SESSION-RESUME und lokale Diagnose-/Build-/Coreartefakte bewusst
außerhalbdesFeaturecommits erhalten. Installierter/testeterSourcezustandentspricht
Commit; keinweitererBuild/RestartfürGitCommitnötig. Runtime15926/GDB15915,
110Bots undCrashaufzeichnung unverändert.
---
# Abgeschlossen03.11.2026: Fahrstuhlfixinstalliert/livegeprüft/110Botsonline
AktuellfinaleNutzerregel: nativeType11Einstieg>=500msReststandzeit,Ausstieg
keineRestzeitprüfung; korrekterHaltweiterPflicht.5MinabwirklicherPassagierzeit
nativTeleportoriginalZielnode(Gegenetage),selbstwennAbbruchdasArbeitszieländert.
Schiff/Zeppelin/Tramunverändert. AbfahrtwährendÜberganghältPassagierbeiType11
fest/versuchtnächstenHaltstattungewolltemAbort; Landrestwegabschließbar.
DeterministischeTestsGrenze499/500,exakt300000/beideRichtungen/keineSchiff-
Ausnahme/Fehlteleport/Abbruchziel/Kurzstop PASS; Deckreturn/GridPASS.
FinalBuild3-j10undInstallationPASS,server15926unterpassivGDB15915,
ready/Corelimitunlimited/Ports8085+8087geprüft. NeueDumpbasis011325.
ECHTERTestbotMorvath150 (registriert,keinAdventureBot) livebeideRichtungen:
run elevator-final-20261103passed(128192ms);nativeArrivedoben01:14:52,
unten01:16:16. ZwischenzeitlichabgefahrenerLiftkorrektalsPassagierüberstanden,
nächsterHaltAusstiegArrived.Kein5MinRescuefürLivetesterzwungen(Fallbackunittested).
Testbot150wiederoffline. Mokrak117benutztenatürlichweiterenLift219022,
oben->unten01:19:05nativeArrived,keineAdminsteuerungdiesesAdventureBots.
Original110Population50/5/50/5vollonline/pending0/Loader1/schema1/errorleer
verifiziert. AlleRecoverylisten/Ergebnisse/Logs/Sourcehinweiseunter
checkpoints/2026-11-03-elevator-exit/(README.md,result.json,Tests,BuildundInstall).
Buildresourcepolicybeachtet:Loaderpausiert+SafeLogoutvorjedemBuild,
kontinuierlicherDrain,Rest10bzw8nach>300secvorShutdownmitverfügbarenFlags
persistiert.KeineEinzelForceLogouts/FlightAbortsfürCompile.InstallnurbeiProzessende.
ShutdownNullcall-Cores003512und010220gesichert;passendeBinarysicherungen
worldserver.crashed(vorigerCheckpoint)undworldserver-first-elevator vorhanden.
RestbotsnachRestartLogin/Positions/TaxiFortschrittgeprüft;35/121nativin
Fraktionshauptstadtgeborgenundverifiziert;48/52Taxi/72Ziel/81Bodenbewegung
verifiziert. KeineTagesplan-/Profilmanipulation/Charakterlöschung.
Nochbekannt: Lags/Shutdown-OPvPCapturePoint-Crash nichtmitdiesemFixbehoben;
Logger.misc3weiterfürnativePhasenmessung,CrashaufzeichnungohneZusatzBreakpoint.
Sourceänderungenuncommitted,keinPush. NutzerfinaleIngameAbnahmeausstehend.
---
# FinalerFahrstuhlbuild3PASS, zweiterShutdowninCoreaufzeichnung
NeuesteRegelimplementiert:Type11Einstieg>=500msRestpause,Ausstieg0ms,
nurwirklicherStillstand/korrekterDock. ÜbergangsabfahrtlöstbeiType11keinen
ungewolltenAbortmehr; LandrestwegauchbeibewegtemLiftabschließbar.5Minpassenger-
FallbackauforiginalZielaktiv. tests_transport-3PASS + vorherDeck/GridPASS,
Build3-j10PASS. Sourcezustandfinal, keineweitereÄnderungnötigvorInstall.
Loaderdurchgängig0/SafeLogoutab01:06:36,erneuteAnforderungvorbuild3protokolliert.
Nach311sec8RestbotsvollständigmitverfügbarenFlagsinshutdown-exception-2.json
undpre-shutdown-2-native.loggesichert; keineEinzelforceLogouts/FlightAborts.
Server13384/GDB13373 normalshutdown10angefordert,erneuterbekannterNULLcall
beimShutdown,Core010220wirdgeschrieben. ProzessendevorInstallationprüfen!
PassendesBinaryworldserver-first-elevatorimCheckpointgesichert(600).
Danncmake--installbuild/debug, passiveGDBLauncherweiter,umask077Consolelog
startup-final.log. Loaderbleibt0bisStartup+8RestbotsRecoverygeprüft.
8GUIDs43/48/52/61/72/81/88/94. Vorherige10RestbotsbeimerstenRestartgeborgen,
35/121Hauptstadtteleportsbereitsverifiziert,jetztweitersicheroffline.
LiveMorvath150ersterRun elevator-roundtrip-20261103physischpassedaberPhaseFailed
beideFahrten; dieseFehlermeldungistnunmitZusatzfixkorrigiert(unittested).
FinaleWiederholungneueRunIDnötig,live-roundtrip.luaenthältjetzt1000msWartenan
jederAnkunft,damitTerminalPhaseauchvorevtTestteardowngeprüftwerdenkann.
VerwendeechtenregistriertenTestbot150,nichtAdventureBots.
NachLiveRunNativeArrivedbeideRichtungenverifizieren,5MinFallbackUnitexakt
300000msgetestet,keinunnötigesLiveFestklemmen. DannLoader1+Config/PopulationReload
und110vollePopulationwiederherstellen/prüfen. KeinCommit/Pushangefordert.
Artefakte checkpoints/2026-11-03-elevator-exit/.
---
# Laufender Fahrstuhlfix: Nutzer ergänzt500msEinstieg, finalerBuildläuft
NeuesteNutzeranforderung: EinstiegType11 mind.500msReststandzeit; Ausstieg
keineRestzeitprüfung, jeweilsnurwirklicherHalt.5MinPassagierFallbackunverändert.
ImplementiertAtDockwiederexaktBudget; Waiting/RequiredPauseType11=500,
RidingExitBudgetType11=0; DeckreturnType11keineRestreserve. Native5MinFallback
undimmutableTargetbereitsinMgr. tests/clientless/test_transport.py inkl499/500
Grenze+beideRichtungen+exakt300000ms+Schiffschutz PASS.
ErsterBuildinstalliertundLiveMorvath150echterTestbotHin/Rückfahrtphysischerfolgreich,
aberNativePhaseFailed, weilAbfahrtwährendspätemEinstiegAbortsetzte.
Zusatzfix: Type11unterbrochenerÜbergang behältFahrt stattAbort; finaleLandstrecke
unabhängigvomabgefahrenenFahrstuhlabschließbar. UnitRegressiondazuPASS.
NochNICHTfinalinstalliert. build-2PASS, build-3-j10läuft/session4663.
KeineanderenunerwartetenSourceänderungen; Branchfeature/clientless-player-core.
AktuellerServer13384mitGDBpassiv/ready/Ports, enthältnurERSTEImplementierung.
Loader0/SafeLogoutall seit01:06ca(build-operation-2.jsonexakt), durchgängig
pausiert; vorbuild3SafeLogouterneutangefordert(build-operation-3.json).
Native8Restbots/combat4/flight4/transport0; keinEinzelforceLogout.
VorInstallationBuild3PASSund5MinabkontinuierlicherDrain-Anforderungprüfen,
RestbotsnochmalsGUIDNameFactionPos+verfügbareFlags/NativeBelegepersistieren,
nativenShutdownundProzessendeabwarten. Shutdowncrashbekannt/Corenichtabbrechen.
PassivesGDBStartscript checkpoints/2026-11-03-passive-restart/start-passive-diagnostic.sh.
Artefakte checkpoints/2026-11-03-elevator-exit/ (build3,test3,Lua,etc).
ErsterMorvathLauf elevator-roundtrip-20261103 istpassed/150offline; Ergebnis
live-roundtrip-first-result.json. FürfinaleLiveprüfungneueseindeutigeRunID,
selbesLua-Skriptmit150verwenden. Vonready_bottomperConsole
clientless transport travel150 orgrimmar_ele_top1; nacharrived_topreverseto
orgrimmar_ele_bottom1. Ergebnis+NativePhaseArrivedproRichtungprüfen.
NacherstemRestart10Restbotsgeprüft;35und121nativnachStormwind/Orgrimmargeborgen
(erneuteProbesbestätigtenBodenstatus), andereTaxi/Autonomieunverändert.
NachfinalemRestartRecoverylistwiederprüfen, Loader1+Config/PopulationReload
undSoll110(50/5/50/5)restaurieren. UserhatvollePopulationwiedererlaubt, recordingfertig.
KeinePush/Commitsangefordert. NeuerShutdownCore003512(altbinaryae0b+)gesichert;
kompatiblealteBinarykopievorhandenworldserver.crashed. ErsteFixBinary13384vor
nächsterInstallfürneuenShutdownCorebeiBedarfseparatsichern.
---
# Fahrstuhlfix implementiert/build+TestsPASS, Installation steht an
Nutzer verlangt Type11 Ein-/Ausstieg ohneReststandzeit, aber nur bei echtemHalt;
5MinutenalsFahrgastfesthängen=>nativTeleportoriginalZielnodeGegenetage.
Source ClientlessTransportMgr.h/.cpp+DeckMgr.cpp geändert. AtDockType11ignoriert
Pausebudget, Deckreturnebenso; neuerPassengerTimer+originalDestination+ACK-
gestützterFallback. KeineAusnahmefürSchiff/Zeppelin/Tram. ResumedPassagierohne
bekanntenEinstieg verwendetnächsteEtage+eindeutigeGegenetagefürFallback.
Tests test_transport.py (beideRichtungen,Stillstand,exakte300000ms,keineSchiffs-
Ausnahme,Abbruchzielbleibt,unzulässigeZiele/Teleportfehler), deckreturnundgrid
PASS. Build-j10PASS. SourcekeineanderenunerwartetenÄnderungen.
VorBuildLoader0 Config+PopulationReload bestätigt; SafeLogoutall00:55:25CET.
Nach>300sec10RestbotsvollständigmitverfügbarenFlags/Positionenpersistiert:
checkpoints/2026-11-03-elevator-exit/shutdown-exception.json+nativeLogs.
KeinEinzelForceLogout/AbbruchvonFlug/Fahrt. Normalshutdown10angefordert;
beimShutdownwiederNULLcall-Crash, GDBschreibtCore
server/debug/crash/worldserver-20261103-003512.core/.backtrace.log.
VorInstallationvollständigesEndevon8437/GDB8425prüfen. PassendesaltesBinary
identischmitcheckpoint2026-11-02-crash-140558/worldserver.crashed(cmpPASS).
Erstdann cmake--installbuild/debug, passiveGDBLauncherweiterverwenden.
Loaderbleibt0durchInstall/Restart. Startupready/Portsverifizieren,10Restbots
manuellonline/Bewegungsstatusprüfen, ggf.nativinFraktionshauptstadtbergen.
SeparaterTestbotMorvath150 fürLiveRoundtripvorbereitet unterelevator-exit/
live-roundtrip.lua, nochNICHTgestartet. KeineAdventureBotsalsTestbotverwenden.
DanachLoader1+Config/PopulationReload und110Populationwiederherstellen.
OriginalConfigpopulation50/5/50/5. KeinPush/Commitbeauftragt.
---
# Mokrak117 Fahrstuhlausstieg diagnostiziert, nochkeinSourcefix
Nutzer vermutete zuhoheReststandzeitsicherung; bestätigt. NativeTransportStatus
Riding top1->bottom1, spawn219021/entry206610, echterPassagier seit00:45:33.
ClientlessTransportMgr.cpp674 ExitBudget=PathLength/run+points*max(100,2diff)+2500.
Unten4Punkte => schon2900ms ohneLaufzeit. DBCAnimation206610 erkenntunten
Stopfenster2133ms(0..2133) und2533ms(30800..33333), oben5166ms.
Daher untenAtDock(...exitBudget) undDeckMgrReadyunmöglich. KeinKoordinaten-
oderfehlenderRoutenbefund erforderlich. Rohdaten/nominalbudgetin
checkpoints/2026-11-03-elevator-exit/diagnosis.json. KeineSourceänderung,
keinBuild/Restart/BotTeleport odererzwungenesDetach. NächsteKorrektur sollte
realephysischeAusstiegsdauer+begründeteReserve nutzen, Punkt-für-PunktTick-
Wartekosten durch kontinuierlicheRückroute vermeiden; nichtbloßRestzeitprüfung
entfernen oderBudgetaufStandzeitkappen. Schiffe/Zeppelineweiterabsichern.
---
# 03.11.2026 Neustart abgeschlossen: alle110Bots wiederonline
Nutzer beendeteFahrstuhlaufnahme und erlaubteNeustart+vollePopulation.
Worldserver8437 unterGDB8425, frischeReady/Ports8085+8087/Corelimitunlimited
verifiziert. ZusätzlicherModellfreigabeBreakpointentfernt; GDBCore+volleThread-
stacks bleibenaktiv. NeueDumpbasis worldserver-20261103-003512.
NativeAbschlussstatus: Loader1/schema1/busy0/errorleer; Pools50/5/50/5alle
vollständigonline, pending0. Insgesamt110Bots, keine128vollausreizen.
Checkpoint checkpoints/2026-11-03-passive-restart/result.json, startup.log,
final-status.log. KeinBuild/Install/Sourcepatch. Logger.misc3 bleibtfürLagdiagnose.
LadephasespikesUpdateSessionsbis7571ms auchohneBreakpoint; LangzeitLagsNICHT
alsbehobenmelden. WährendShutdown00:34erneuterNULLcallbeiOPvPCapturePoint-
Destruktion, Core9.3GB+volleStacks gesichertuntervorigerDumpbasis
worldserver-20261102-215114; separateBaustelle, keinFixbehaupten.
AlterWorldserverbeendetundtmuxwegvorNeustart. AktuellerServeroperational.
---
# 03.11.2026 Neustart nach abgeschlossener Aufnahme läuft
Nutzer bestätigt Aufnahme vorerst beendet und erlaubt sämtlicheBots wieder.
OriginalPopulation50/5/50/5 wiederhergestellt. VorShutdown SafeLogoutall,
dann normalserver shutdown10. ShutdownSIGSEGV in OPvPCapturePoint-Destruktion
(NULLcall), Core9.3GB und volleStacks unterserver/debug/crash/
worldserver-20261102-215114.core/.backtrace.log gesichert. KeinSourcefix.
AlteProzesse2302/2220 vollständigbeendet, tmuxweg, erst dann Neustart.
NeuerWorldserver8437/GDB8425, passiveGDBohneModellfreigabeBreakpoint,
frischeReady/Ports8085+8087/Corelimitunlimited verifiziert. ConfigLoader1
undConfig+PopulationReload ausgeführt; automatischePopulation lädtnoch.
NeueDumpbasis worldserver-20261103-003512. Checkpoint
checkpoints/2026-11-03-passive-restart/, startup.log undStartscriptdarin.
NächsterSchritt: bisSollbestand110verifizieren, kurzePhasenzeitmessung,
Ergebnisnotieren. Logger.misc3 bleibtfürLags aktiv, keinLagfixbehaupten.
---
# Laufende Nutzeraufnahme: KEIN NEUSTART bei Lagdiagnose
Nutzer meldet massive Lags nach Population10. Auf Rückfrage explizit:
„Nein, Aufnahme läuft noch“. Keinen Restart/DebuggerDetach/RecordingReset.
Details checkpoints/2026-11-02-lag-diagnostics/README.md. NativePhaselogging
via temporäremLogger.misc3 aktiviert, PausenMapMgrbis1817ms/Terrain206ms belegt;
Botcontrollersnur~0.35-0.4s/30s. Rootcauseoffen, GDBbreakpointnichtbewiesen.
Keine aktuelle Swaplast; VMausreichendRAM. KeinBuild/Sourcepatch.
Start-passive-diagnostic.sh für späterenVergleich ohneModellFreigabeBreakpoint
vorbereitet, NICHT gestartet. CoreDump/Threadstacks bleibenauchdannaktiv.
BisAufnahmegespeichert bleibtWorldserver2302/GDB2220 unverändert, zehnBots,
Loader0. MesslogsundProzesssamplesgesichert. KeinLagfixbehaupten.
---
# Aktuell: Population auf zehn Bots reduziert für Fahrstuhlaufzeichnung
Nutzer meldete Lag beim Aufzeichnen und verlangte zehnBots. Configzielwerte
Alliance.Persistent5/Temporary0/Horde.Persistent5/Temporary0 gesetzt.
Loader0 per Config+PopulationReload während laufender Nutzeraufzeichnung
beibehalten; keine automatische Auffüllung/Rotation. VorherigeWerte im
checkpoints/2026-11-02-population-10/operation.json (50/5/50/5,Enabled1).
100Bots Logout angefordert:82 sicher ausgeloggt;18 nach verbleibendem
Combat/Transport/Flight über normalen nativen clientless logout ausgeloggt.
Keine Prozessbeendigung, kein Restart, keine Einzeldatenbank-Logoutmanipulation.
Abschluss NATIV bestätigt pending0/sessions10, beidepersistentPools5online,
temporärePools0online, CPC_PERF players10. Worldserver2302/GDB2220 aktiv.
Verbleibend26/33/35/39/41 Allianz und34/36/40/42/44 Horde. Keine Botlöschung,
keine Tagesplan-/Profiländerung. Nach Nutzeraufzeichnung Loader ggf.wieder
aktivieren, Zehner-Ziel beibehalten bis andersbeauftragt; nicht110restaurieren.
---
# Volakmar nach Orgrimmar zurückgebracht und wieder online
Nutzerkorrektur: Volakmar128 ist regulärer AdventureBot, kein separater Testbot.
Auf ausdrücklichen Auftrag nativ offline nach Orgrimmar teleportiert,
DB map1/1569.97/-4397.41/16.0472 bestätigt; danach clientless login128.
DB online1 an derselben Position bestätigt. Loader wiederauf1 restauriert,
reload config+clientless population reload ausgeführt. Keine Profil-/Planänderung.
GDB-Worldserver2302 und Crashaufzeichnung unverändert aktiv.
Für künftige gezielte Reproversuche separaten Testbot verwenden.
---
# Objekt-Repro: Level80 Volakmar128 hingebracht und ausgeloggt
Nutzerauftrag erfüllt: zur Spawn59235-Position map5715988.04/4473.78/-87.3617
nativ teleportiert. Native Inspect kurz danach5981.088/4477.738/-87.755,
Bot wurde lokal von28373 angegriffen, geriet in defensiveCombat und floh.
SafeLogout wartete aufCombat; anschließend auf expliziten Nutzerlogoutauftrag
normalen clientless logout128 ausgeführt, native Offline und DBonline0 bestätigt.
Letzte gespeicherte Position5971.01/4495.2/-92.1969, health877. Kein Todbelegt.
Temporären GM-Teleport vollständig entfernt+Reload. Worldserver2302 läuftweiter.
Loader vorTest von1auf0+Config/PopulationReload pausiert, bleibt0 damit Testbot
nicht automatisch in den eben verlassenen Grid zurückkehrt. Andere Bots laufen
weiter. Nach gezieltem Reprofenster Loader1+beideReloads restaurieren; keine
sonstigen Pläne/Profile geändert. before/after/evidence unter
checkpoints/2026-11-02-crash-140558/object-repro/. Debugger weiterhin aktiv.
---
# VM-Neustart 02.11.2026 21:51 CET: Diagnosebetrieb wieder gestartet
Auf Nutzerwunsch identischer GDB-Launcher samt Modellfreigabe-Logpoint gestartet.
Vorher keine Worldserver-/GDB-Prozesse oder tmuxSession vorhanden.
Worldserver PID2302 unter GDB2220, tmuxvcore-worldserver. Aktuelle ready-Meldung
in frischem Server.log, Ports8085/8087 LISTEN, Prozess lebendig, Corelimitunlimited
bestätigt. Loader.Enabled=1 unverändert. Keine Builds/Source-/DB-/Planänderungen.
Neue Diagnosekonsole: checkpoints/2026-11-02-crash-140558/vm-restart-console.log.
Bei Crash automatisch server/debug/crash/worldserver-20261102-215114.core
und worldserver-20261102-215114.backtrace.log (inkl. aller Threadstacks).
Modellfreigaben weiterhin über model-lifetime.gdb erfasst. Bei Crash zuerst
Core/Binary sichern und auswerten; keine konkrete Fehlerbehebung behauptet.
---
# Aktuell 02.11.2026: erneuten Crash ausgewertet
Nutzer meldete Server offline. GDB266570/Worldserver266615 waren nach Crash
14:05:58 beendet. Core und vollständige Stacks erfolgreich gesichert; passende
Executable separat kopiert. ZUERST checkpoint2026-11-02-crash-140558/README.md
lesen. SIGSEGV std::_Hash_bytes beim GridUnload eines Unstable Explosives,
Spawn59235/map571. GameObjectModel verweist auf Speicher, der nun
Movement::Spline<int> enthält; Modellcache hat dasselbe Modell unter anderer
Adresse. Stale Pointer/Allocation reuse belegt, konkrete vorzeitige Freigabe
noch NICHT zugeordnet. Keine spekulative Sourcekorrektur und kein Build.
Original11:05 vectorassert ist nicht als gleiche Ursache bewiesen.
Neustart unverändertes Binary mit GDB und zusätzlichem nichtstoppenden
Freigabelogpoint für Sc_Plaguebomb_Orange.m2 (inkl. NUL-Variante).
Launcher/startup log im neuen Checkpoint. Loaderoriginal1 restauriert;
Startupprüfung und native PopulationReload siehe neuesten Checkpointabschluss.
Keinen Raidtest neu gestartet. Auf erneuten Crash muss nicht aktiv gewartetwerden.
---
# Nutzerpause: Crashdiagnose wartet auf erneuten Absturz
Zwischenauftrag erledigt: Anleitung für Fahrstuhlaufnahmen unter
`doc/clientless/fahrstuehle-aufzeichnen.md` erstellt, Befehle am aktuellen
TransportMgr/Recorder geprüft. AllgemeineTransportdoku hinsichtlich neuem
Entfernungskostenmodell aktualisiert. Keine Server-/DB-/Sourceänderungen,
keinBuild/Restart; laufende GDB-Crashaufzeichnung unverändert.
Nutzer ausdrücklich: Crash kann Stunden dauern, nicht aktiv weiterwarten;
er ruft erneut auf, sobald er wieder auftritt. Raidtest hat aktuell keinen Vorrang.
Gesicherter Stand: checkpoints/2026-11-02-crash-110519/README.md — ZUERST LESEN.
Worldserver266615 unter GDB266570 in tmuxvcore-worldserver, ready/Ports8085+8087
und corelimitunlimited verifiziert. Gleiche110Bots manuellgeladen, normale
Autonomie läuft; Loader0 friert Bestand fürRepro ein. KeinBuild/Sourcefix erfolgt.
NächsterfatalerSignalstop erzeugt automatisch
server/debug/crash/worldserver-20261102-114738.core und .backtrace.log
(volleThreadstacks). Binary bisAuswertungnichtaustauschen.
Original11:05:19: conststd::vector<unsigned int> Indexassert, dannSIGABRT6,
AbortHandler erzeugt bewusstSIGSEGV. TatsächlicherAufrufernochunbekannt.
Originalcorefehltewegenlimit0; jetzigeAufzeichnungistgeprüftaktiv.
StatischeBIHIndexprüfung27646Bäume ohneFehler. Spawnprüfung1ungeprüfteAnomalie
undfehlendeModelle protokolliert; keineursächlicheZuordnungbehaupten.
BeiWiederaufnahmeaktuellenGDB-Backtrace/Coreauswerten, nichtalteNov1Core.
AktiveBeobachterRaid1100beendet, eigeneCrash-Konsolewirdweiteraufgezeichnet.
LoaderamEndederUntersuchungaufaltenWert1restaurieren+PopulationReload.
---
# Wiederholung 02.11.2026, Gruppenbildung10 / Raid11:00
Nutzer: selbenZehnertest erneut durchführen. Alle10 pergezieltemSafeLogout
sauberofflinegebracht, temporärerLoaderpause mitPopulationReload verifiziert.
NurderenalteHandoff-/InstanceVisit-Zustände gesichert/entfernt, nativeTeleports
zurGoldenenRose, Tagespläne10groupformation/the_gilded_rose und11raid/
instance_visit_at_6354_d0 füralle20Zeilenvalidiert. Alle10wiederonline.
Um10:52vollständig Gruppe2 LeaderBrynda165,159,160,161,162,163,164,165,166,
167,176.2Tank/2Heal/6Damage. NativealleOnSite/waitingatthemeetingpoint.
NatürlicheFrühaufbruchlogik armiert10:56:44MEZ; Raidblockbleibt11:00.
KeineerzwungeneManagerzuweisung, keinBuild/Serverrestart, anderePläneunverändert.
OriginalLoaderkonfiguration restauriert/PopulationReload; Tempteleportgelöscht.
NeueRead-onlyBeobachtung bis12MEZ:
service vcore-adventure-raid-observer-20261102-1100.service,
checkpoints/2026-11-02-1100-raid-test/ (eigeneRohlogs, Snapshots, Manifest).
Voriger10UhrObserverbeendetundGrenzeimLifecycleprotokolliert. Nochkeine
Ankunft/Instanzeintritt fürdiesenneuenLaufbehaupten. Flugfixae0b7513d9
installiert; bekannterGroundSafety-Fehler bleibtunverändert.
---
# Aktuell 02.11.2026, 10:00: Shared-Flight-Landepunkt/Flugpausen korrigiert
Nutzer meldete Nachfolger kehren über Plattform um und fliegen stockend.
@@ -18,11 +18,13 @@
#include "BattlefieldMgr.h"
#include "Containers.h"
#include "DatabaseEnv.h"
#include "DBCStores.h"
#include "Log.h"
#include "Map.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellAuraEffects.h"
namespace
{
@@ -141,6 +143,57 @@ bool BattlefieldMgr::IsWorldPvpArea(uint32 zoneId) const
return std::find(BattlefieldIdToZoneId.begin(), BattlefieldIdToZoneId.end(), zoneId) != BattlefieldIdToZoneId.end();
}
bool BattlefieldMgr::IsWintergraspFlightAllowed(uint32 mapId, uint32 areaId) const
{
// Cataclysm's static mount flags omit flight throughout Wintergrasp.
// The actual restriction is temporary and belongs to the battle state.
if (mapId != 571 || !DBCManager::IsInArea(areaId, 4197))
return false;
for (auto const& [map, battlefields] : _battlefieldsByMap)
if (map->GetId() == mapId)
for (auto const& battlefield : battlefields)
if (battlefield->GetZoneId() == 4197 && battlefield->IsEnabled() &&
!battlefield->CanFlyIn())
return false;
return true;
}
void BattlefieldMgr::UpdateWintergraspFlight(Player* player) const
{
// The client also needs this native mount-permission aura; server-only
// AreaTable exceptions do not enable every mount in the client UI.
constexpr uint32 flightPermission = 91262;
bool allowed = IsWintergraspFlightAllowed(player->GetMapId(), player->GetAreaId());
uint32 otherRestrictions = 0;
bool hasOtherRestrictions = false;
for (AuraEffect const* effect : player->GetAuraEffectsByType(SPELL_AURA_MOUNT_RESTRICTIONS))
if (effect->GetId() != flightPermission)
{
hasOtherRestrictions = true;
otherRestrictions |= uint32(effect->GetMiscValue());
}
if (hasOtherRestrictions && !(otherRestrictions & uint32(AreaMountFlags::AllowFlyingMounts)))
allowed = false;
if (allowed)
{
if (!player->HasAura(flightPermission))
player->AddAura(flightPermission, player);
}
else
player->RemoveAurasDueToSpell(flightPermission);
}
void BattlefieldMgr::UpdateWintergraspFlight(Map* map) const
{
for (auto const& reference : map->GetPlayers())
if (Player* player = reference.GetSource())
if (player->GetZoneId() == 4197)
{
UpdateWintergraspFlight(player);
player->UpdateMountCapability();
}
}
Battlefield* BattlefieldMgr::GetBattlefieldToZoneId(Map const* map, uint32 zoneId)
{
auto itr = _battlefieldsByZone.find({ map, zoneId });
@@ -52,6 +52,9 @@ class TC_GAME_API BattlefieldMgr
void HandlePlayerLeaveZone(Player* player, uint32 zoneId);
bool IsWorldPvpArea(uint32 zoneId) const;
bool IsWintergraspFlightAllowed(uint32 mapId, uint32 areaId) const;
void UpdateWintergraspFlight(Player* player) const;
void UpdateWintergraspFlight(Map* map) const;
// return assigned battlefield
Battlefield* GetBattlefieldToZoneId(Map const* map, uint32 zoneId);
@@ -7086,6 +7086,7 @@ void Player::UpdateArea(uint32 newArea)
else
RemoveRestFlag(REST_FLAG_IN_FACTION_AREA);
sBattlefieldMgr->UpdateWintergraspFlight(this);
UpdateMountCapability();
}
+4
View File
@@ -7911,7 +7911,11 @@ MountCapabilityEntry const* Unit::GetMountCapability(uint32 mountType) const
mountFlags |= AreaMountFlags(auraEffect->GetMiscValue());
}
else if (AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(areaId))
{
mountFlags = areaTable->GetMountFlags();
if (sBattlefieldMgr->IsWintergraspFlightAllowed(GetMapId(), areaId))
mountFlags |= AreaMountFlags::AllowFlyingMounts;
}
ZLiquidStatus liquidStatus = GetLiquidStatus();
isUnderwater = (liquidStatus & LIQUID_MAP_UNDER_WATER) != 0;
+5
View File
@@ -17,6 +17,7 @@
#include "SpellInfo.h"
#include "Battleground.h"
#include "BattlefieldMgr.h"
#include "Corpse.h"
#include "Creature.h"
#include "DBCStores.h"
@@ -1797,7 +1798,11 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
mountFlags |= AreaMountFlags(auraEffect->GetMiscValue());
}
else if (AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(area_id))
{
mountFlags = areaTable->GetMountFlags();
if (sBattlefieldMgr->IsWintergraspFlightAllowed(map_id, area_id))
mountFlags |= AreaMountFlags::AllowFlyingMounts;
}
if (!(mountFlags.HasFlag(AreaMountFlags::AllowFlyingMounts)))
return SPELL_FAILED_INCORRECT_AREA;
@@ -471,10 +471,25 @@ bool AdventureGroupTravelMgr::ValidateGroundPath(Player* player,std::vector<Posi
{
float t=float(step)/steps,x=a.GetPositionX()+(b.GetPositionX()-a.GetPositionX())*t,y=a.GetPositionY()+(b.GetPositionY()-a.GetPositionY())*t,z=a.GetPositionZ()+(b.GetPositionZ()-a.GetPositionZ())*t;
float floor=player->GetMap()->GetHeight(player->GetPhaseShift(),x,y,z+2,true,6);
if(floor<=INVALID_HEIGHT || !AdventureGroupTravelPolicy::GroundSample(z,floor,last,length/steps))return false;
if(floor<=INVALID_HEIGHT || !AdventureGroupTravelPolicy::GroundSample(z,floor,last,length/steps))
{
TC_LOG_WARN("server.adventurebot.navigation",
"GROUP_GROUND_REJECT guid=%u map=%u check='ground' segment=%u sample=%u/%u position=(%.3f %.3f %.3f) floor=%.3f previousFloor=%.3f heightError=%.3f floorStep=%.3f allowedHeightError=%.3f allowedFloorStep=%.3f",
player->GetGUID().GetCounter(),player->GetMapId(),uint32(i),step,steps,x,y,z,floor,last,
std::fabs(floor-z),std::fabs(floor-last),AdventureGroupTravelPolicy::MaxGroundStep,
AdventureGroupTravelPolicy::MaxGroundStep+AdventureGroupTravelPolicy::MaxGroundSlope*length/steps);
return false;
}
last=floor;
}
if(!player->GetMap()->isInLineOfSight(player->GetPhaseShift(),a.GetPositionX(),a.GetPositionY(),a.GetPositionZ()+1,b.GetPositionX(),b.GetPositionY(),b.GetPositionZ()+1,LINEOFSIGHT_ALL_CHECKS,VMAP::ModelIgnoreFlags(0)))return false;
if(!player->GetMap()->isInLineOfSight(player->GetPhaseShift(),a.GetPositionX(),a.GetPositionY(),a.GetPositionZ()+1,b.GetPositionX(),b.GetPositionY(),b.GetPositionZ()+1,LINEOFSIGHT_ALL_CHECKS,VMAP::ModelIgnoreFlags(0)))
{
TC_LOG_WARN("server.adventurebot.navigation",
"GROUP_GROUND_REJECT guid=%u map=%u check='line-of-sight' segment=%u from=(%.3f %.3f %.3f) to=(%.3f %.3f %.3f)",
player->GetGUID().GetCounter(),player->GetMapId(),uint32(i),a.GetPositionX(),a.GetPositionY(),
a.GetPositionZ()+1,b.GetPositionX(),b.GetPositionY(),b.GetPositionZ()+1);
return false;
}
}
return true;
}
@@ -2272,6 +2272,13 @@ bool ClientlessActionExecutorMgr::RecoverTravel(
{record.RescueActive=false;record.RescueWalkFailed=true;}
if (failedEdgeDatabaseId)
record.FailedEdgeDatabaseIds.insert(failedEdgeDatabaseId);
// StartTravel can accept a request whose first spline is subsequently
// rejected by the owner validator. Remember dynamic bridges here as well.
if (!failedEdgeDatabaseId && reason.rfind("route-local-", 0) == 0 &&
record.RouteStep > 0 && record.RouteStep < record.Route.size() &&
record.Route[record.RouteStep].EdgeType == "local_bridge")
record.FailedBridgeKeys.insert(record.Route[record.RouteStep - 1].NodeKey +
"->" + record.Route[record.RouteStep].NodeKey);
// A failed initial local approach must not be tried five times at the same spot.
if (!failedEdgeDatabaseId && record.RouteStep == 0 && !record.Route.empty() &&
reason.rfind("route-local-", 0) == 0)
@@ -159,7 +159,10 @@ float ClientlessFlightMgr::Estimate(Player const * player, uint32 map, Position
uint32 const area = AreaZone(player, map, from).first;
if (auto const * data = sAreaTableStore.LookupEntry(area))
{
bool const dynamicRules = data->World_pvp_ID != 0 ||(map == player->GetMapId() && area == player->GetAreaId() && player->HasAuraType(SPELL_AURA_MOUNT_RESTRICTIONS));
bool const wintergrasp = map == 571 && DBCManager::IsInArea(area, 4197);
bool const wintergraspFlight = sBattlefieldMgr->IsWintergraspFlightAllowed(map, area);
if (wintergrasp && !wintergraspFlight) return Infinity();
bool const dynamicRules = wintergraspFlight || data->World_pvp_ID != 0 ||(map == player->GetMapId() && area == player->GetAreaId() && player->HasAuraType(SPELL_AURA_MOUNT_RESTRICTIONS));
if (! dynamicRules && ! data->GetMountFlags().HasFlag(AreaMountFlags::AllowFlyingMounts)) return Infinity();
}
// Unknown terrain permission is an estimate only; native mount capability
+4 -3
View File
@@ -124,6 +124,10 @@ namespace ClientlessFlightPath
if (! here.Valid || ! end.Valid || std::fabs(end.Ground - goal.Z) > 2.5f) return
{
};
// Issuing a takeoff spline is not proof of actual clearance. Handoffs
// may replan while that spline is still close to its support surface.
if (!memory.Departed && from.Z >= here.Ground + cfg.Safety)
memory.Departed = true;
using Phase = Memory::ElevatedPhase;
if (memory.Elevated != Phase::None && Distance(memory.ElevatedGoal,goal)>0.1f)
memory.Elevated=Phase::None;
@@ -280,7 +284,6 @@ namespace ClientlessFlightPath
// must not postpone descent until directly above the destination.
if (openApproach)
{
memory.Departed = true;
return best;
}
}
@@ -294,11 +297,9 @@ namespace ClientlessFlightPath
Point vertical{from.X,from.Y,top};
if (top > from.Z + 2.0f && Corridor(from,vertical,goal,cfg,sample,ray,true))
{
memory.Departed=true;
return {vertical,true,false,false};
}
}
if (best.Valid) memory.Departed = true;
return best;
}
struct SharedTrail
@@ -231,6 +231,8 @@ int Skill(lua_State* L)
if(!sSkillLineStore.LookupEntry(skill) || value>maximum)return luaL_error(L,"invalid skill or skill value exceeds maximum");
p->SetSkill(uint16(skill),p->GetSkillStep(uint16(skill)),uint16(value),uint16(maximum));lua_pushboolean(L,p->GetPureSkillValue(skill)==value);return 1;
}
int HasAura(lua_State* L){auto p=Actor(L);lua_pushboolean(L,p->HasAura(Number(L,2)));return 1;}
int RemoveAura(lua_State* L){auto p=Actor(L);p->RemoveAurasDueToSpell(Number(L,2));return 0;}
int Count(lua_State* L){auto p=Actor(L);lua_pushinteger(L,p->GetItemCount(Number(L,2),false));return 1;}
int Quest(lua_State* L){auto p=Actor(L);auto id=Number(L,2);lua_pushinteger(L,p->GetQuestStatus(id));lua_pushboolean(L,p->GetQuestRewardStatus(id));return 2;}
int Find(lua_State* L)
@@ -425,7 +427,7 @@ bool Start(std::string const& id,fs::path path,std::string& error)
for(auto name:{"io","os","package","debug","dofile","loadfile","require","load","collectgarbage","coroutine","pcall","xpcall"}){lua_pushnil(L);lua_setglobal(L,name);}
lua_newtable(L);
for(auto const& fn:std::initializer_list<std::pair<char const*,lua_CFunction>>{
{"npc_hello",NpcHello},{"menu",Menu},{"spellclick",SpellClick},{"exit_vehicle",ExitVehicle},{"request_cast",RequestCast},{"request_cast_at",RequestCastAt},{"use_item_at",UseItemAt},{"area_trigger",AreaTrigger},{"inventory",Inventory},{"stop",Stop},{"now_ms",Now},{"spawn",Spawn},{"online",Online},{"_create",Create},{"_create_result",CreateResult},{"wait",Wait},{"state",Snapshot},{"teleport",Teleport},{"level",Level},{"stats",Stats},{"stat",Stat},{"learn",Learn},{"item",Item},{"equip",Equip},{"clear_slot",ClearSlot},{"remove_item",RemoveItem},{"skill",Skill},{"item_count",Count},{"quest",Quest},{"use",Use},{"hello",Hello},{"accept",Accept},{"abandon",Abandon},{"reward",Reward},{"gossip",Gossip},{"cast",Cast},{"move",Move},{"face",Face},{"attack",Attack},{"target_state",TargetState},{"objectives",Objectives},{"request_reward",RequestReward},{"loot",Loot},{"loot_item",LootItem},{"loot_release",LootRelease},{"use_item",UseItem},{"record",Record},{"check",Check}})Bind(L,r.get(),fn.first,fn.second);
{"npc_hello",NpcHello},{"menu",Menu},{"spellclick",SpellClick},{"exit_vehicle",ExitVehicle},{"request_cast",RequestCast},{"request_cast_at",RequestCastAt},{"use_item_at",UseItemAt},{"area_trigger",AreaTrigger},{"inventory",Inventory},{"stop",Stop},{"now_ms",Now},{"spawn",Spawn},{"online",Online},{"_create",Create},{"_create_result",CreateResult},{"wait",Wait},{"state",Snapshot},{"teleport",Teleport},{"level",Level},{"stats",Stats},{"stat",Stat},{"learn",Learn},{"item",Item},{"equip",Equip},{"clear_slot",ClearSlot},{"remove_item",RemoveItem},{"skill",Skill},{"has_aura",HasAura},{"remove_aura",RemoveAura},{"item_count",Count},{"quest",Quest},{"use",Use},{"hello",Hello},{"accept",Accept},{"abandon",Abandon},{"reward",Reward},{"gossip",Gossip},{"cast",Cast},{"move",Move},{"face",Face},{"attack",Attack},{"target_state",TargetState},{"objectives",Objectives},{"request_reward",RequestReward},{"loot",Loot},{"loot_item",LootItem},{"loot_release",LootRelease},{"use_item",UseItem},{"record",Record},{"check",Check}})Bind(L,r.get(),fn.first,fn.second);
Bind(L,r.get(),"nearest_creature",Nearest);Bind(L,r.get(),"nearest_object",Nearest,1);
Bind(L,r.get(),"creature",Find);Bind(L,r.get(),"object",Find,1);lua_setglobal(L,"testbot");
char const* helpers=R"lua(
@@ -540,6 +540,7 @@ bool BattlefieldWG::SetupBattlefield()
void BattlefieldWG::OnBattleStart()
{
sBattlefieldMgr->UpdateWintergraspFlight(m_Map);
// Spawn titan relic
if (GameObject* relic = SpawnGameObject(GO_WINTERGRASP_TITAN_S_RELIC, WintergraspRelicPos, WintergraspRelicRot))
{
@@ -628,6 +629,7 @@ void BattlefieldWG::UpdateCounterVehicle(bool init)
void BattlefieldWG::OnBattleEnd(bool endByTimer)
{
sBattlefieldMgr->UpdateWintergraspFlight(m_Map);
// Remove relic
if (m_titansRelicGUID)
if (GameObject* relic = GetGameObject(m_titansRelicGUID))
@@ -193,8 +193,8 @@ bool OutdoorPvPZM::SetupOutdoorPvP()
for (uint8 i = 0; i < OutdoorPvPZMBuffZonesNum; ++i)
RegisterZone(OutdoorPvPZMBuffZones[i]);
m_Graveyard = std::make_unique<OPvPCapturePointZM_Graveyard>(this);
AddCapturePoint(m_Graveyard.get()); // though the update function isn't used, the handleusego is!
m_Graveyard = new OPvPCapturePointZM_Graveyard(this);
AddCapturePoint(m_Graveyard); // though the update function isn't used, the handleusego is!
return true;
}
+2 -1
View File
@@ -169,7 +169,8 @@ class OutdoorPvPZM : public OutdoorPvP
void SetHordeTowersControlled(uint32 count);
private:
std::unique_ptr<OPvPCapturePointZM_Graveyard> m_Graveyard;
// Owned by OutdoorPvP::m_capturePoints after AddCapturePoint.
OPvPCapturePointZM_Graveyard* m_Graveyard = nullptr;
uint32 m_AllianceTowersControlled;
uint32 m_HordeTowersControlled;
@@ -23,6 +23,7 @@ code=r'''
#include <set>
using uint32=unsigned;
#define TC_GAME_API
#define TC_LOG_WARN(...) ((void)0)
constexpr float INVALID_HEIGHT=-100000;
constexpr int LINEOFSIGHT_ALL_CHECKS=0,CMSG_AREATRIGGER=0;
namespace VMAP{enum class ModelIgnoreFlags{None};}
@@ -0,0 +1,30 @@
"""Verify delayed dynamic bridge rejection blocks only its directed connection."""
from pathlib import Path
import subprocess, tempfile
root = Path(__file__).resolve().parents[2]
source = (root / "src/server/game/World/ClientlessActionExecutorMgr.cpp").read_text()
start = source.index(' if (!failedEdgeDatabaseId && reason.rfind("route-local-", 0) == 0 &&')
end = source.index(' // A failed initial local approach', start)
code = r'''
#include <string>
#include <vector>
#include <unordered_set>
#include <cassert>
struct Step {std::string NodeKey,EdgeType;};
struct Record {unsigned RouteStep;std::vector<Step> Route;std::unordered_set<std::string> FailedBridgeKeys;};
void reject(Record& record,unsigned failedEdgeDatabaseId,std::string reason){
''' + source[start:end] + r'''
}
int main(){Record r{1,{{"taxi_2","start"},{"stormwind_tradecenter","local_bridge"}}, {}};
reject(r,0,"route-local-PathRejected");assert(r.FailedBridgeKeys.count("taxi_2->stormwind_tradecenter"));
assert(!r.FailedBridgeKeys.count("stormwind_tradecenter->taxi_2"));
r.FailedBridgeKeys.clear();reject(r,15,"route-local-PathRejected");assert(r.FailedBridgeKeys.empty());
r.RouteStep=0;reject(r,0,"route-local-PathRejected");assert(r.FailedBridgeKeys.empty());
r.RouteStep=1;r.Route[1].EdgeType="free_flight";reject(r,0,"route-local-PathRejected");assert(r.FailedBridgeKeys.empty());}
'''
with tempfile.TemporaryDirectory(prefix="vcore-dynamic-bridge-") as directory:
path=Path(directory)
(path/"test.cpp").write_text(code)
subprocess.run(["c++","-std=c++17",str(path/"test.cpp"),"-o",str(path/"test")],check=True)
subprocess.run([str(path/"test")],check=True)
print("Delayed bridge rejection, direction, persistent edges and non-bridge exclusions PASS")
+8
View File
@@ -51,6 +51,8 @@ struct Profile{bool CanFreeFly=true;std::vector<Mount> FlightMounts{{}};} profil
struct Lua{auto GetAdventureProfile(uint32){return &profile;}} lua;
struct Config{int reads=0;bool enabled=true;bool GetBoolDefault(const char*,bool){++reads;return enabled;}float GetFloatDefault(const char*,float v){++reads;return v;}std::string GetStringDefault(const char*,const char*v){++reads;return v;}} config;
auto sClientlessLuaEngine=&lua;auto sConfigMgr=&config;
struct DBCManager{static bool IsInArea(uint32 area,uint32 zone){return area==zone || (zone==4197&&area==4538);}};
struct Battlefields{bool war=false;bool IsWintergraspFlightAllowed(uint32 map,uint32 area){return map==571&&DBCManager::IsInArea(area,4197)&&!war;}} battlefield;auto sBattlefieldMgr=&battlefield;
struct SpellMgr{void* GetSpellInfo(uint32){return this;}} spells;auto sSpellMgr=&spells;
uint32 FlightType(void*){return 1;}
struct MapEntry{uint32 MapType=0;} entry;struct Maps{auto LookupEntry(uint32){return &entry;}} maps;auto& sMapStore=maps;
@@ -123,6 +125,12 @@ int main(){
profile.CanFreeFly=false;assert(!mgr.Enabled(&p));
mgr.BeginPlanning();assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));
profile.CanFreeFly=true;
// Static Wintergrasp subareas lack flight flags, but peace permits flight.
mgr.areaCode=4538;mgr.zoneCode=4197;area.fly=false;p.cold=true;
assert(std::isfinite(mgr.Estimate(&p,571,a,b)));
battlefield.war=true;assert(!std::isfinite(mgr.Estimate(&p,571,a,b)));
battlefield.war=false;assert(std::isfinite(mgr.Estimate(&p,571,a,b)));
mgr.areaCode=87;mgr.zoneCode=12;assert(!std::isfinite(mgr.Estimate(&p,571,a,b)));area.fly=true;
int beforeInterrupts=p.interrupts;Record approach;approach.ApproachingDeparture=true;approach.Status.State=ClientlessFlightState::Mounting;mgr.Fail(&p,approach,"interrupted");assert(travel.cancels==1&&!approach.ApproachingDeparture&&approach.Status.State==ClientlessFlightState::Failed&&p.interrupts==beforeInterrupts);
Record revoked;p.canFly=false;mgr.Fail(&p,revoked,"permission lost");assert(revoked.Status.State==ClientlessFlightState::Failed&&!revoked.Returning);
}
@@ -0,0 +1,16 @@
"""Replan during takeoff without prematurely demanding cruise clearance."""
from pathlib import Path
import subprocess, tempfile
root = Path(__file__).resolve().parents[2]
code = r'''
#include "ClientlessFlightPath.h"
#include <cassert>
using namespace ClientlessFlightPath;
int main(){Settings c;Memory m;auto sample=[](float,float){return Surface{94.314f,550,true};};auto ray=[](Point const&,Point const&){return true;};Point goal{-8186,419,94.314f};auto n=Next({-8829,624,94.314f},goal,c,m,sample,ray);assert(n.Valid&&!m.Departed);n=Next({-8826.7f,622.306f,96.4122f},goal,c,m,sample,ray);assert(n.Valid&&!m.Departed);n=Next({-8800,610,104},goal,c,m,sample,ray);assert(n.Valid&&m.Departed);}
'''
with tempfile.TemporaryDirectory(prefix="vcore-takeoff-handoff-") as directory:
path = Path(directory)
(path / "test.cpp").write_text(code)
subprocess.run(["c++", "-std=c++17", "-I" + str(root / "src/server/game/World"), str(path / "test.cpp"), "-o", str(path / "test")], check=True)
subprocess.run([str(path / "test")], check=True)
print("Takeoff handoff at two yards and promotion at real cruise clearance PASS")
@@ -0,0 +1,39 @@
"""Run production WG client permission synchronization and battle refresh."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
s=(root/"src/server/game/Battlefield/BattlefieldMgr.cpp").read_text()
a=s.index("void BattlefieldMgr::UpdateWintergraspFlight(Player*")
b=s.index("\nBattlefield* BattlefieldMgr::GetBattlefieldToZoneId",a)
code=r'''
#include <cassert>
#include <vector>
#include <set>
using uint32=unsigned;
constexpr unsigned SPELL_AURA_MOUNT_RESTRICTIONS=336;
enum class AreaMountFlags:unsigned{AllowFlyingMounts=2};
struct AuraEffect {unsigned id,misc;unsigned GetId()const{return id;}int GetMiscValue()const{return misc;}};
struct Player {unsigned zone=4197,area=4197,map=571;int casts=0,updates=0;std::set<unsigned> auras;std::vector<AuraEffect const*> effects;
unsigned GetMapId()const{return map;}unsigned GetAreaId()const{return area;}unsigned GetZoneId()const{return zone;}
auto const& GetAuraEffectsByType(unsigned)const{return effects;}bool HasAura(unsigned id)const{return auras.count(id);}
void AddAura(unsigned id,Player*){auras.insert(id);++casts;}void RemoveAurasDueToSpell(unsigned id){auras.erase(id);}void UpdateMountCapability(){++updates;}};
struct Reference {Player* player;Player* GetSource()const{return player;}};
struct Map {std::vector<Reference> players;auto const& GetPlayers()const{return players;}};
struct BattlefieldMgr {bool permitted=true;bool IsWintergraspFlightAllowed(unsigned map,unsigned area)const{return permitted&&map==571&&(area==4197||area==4538);}void UpdateWintergraspFlight(Player*)const;void UpdateWintergraspFlight(Map*)const;};
'''+s[a:b]+r'''
int main(){BattlefieldMgr m;Player p,out;out.zone=210;out.area=210;Map map{{{&p},{&out}}};
m.UpdateWintergraspFlight(&map);assert(p.HasAura(91262)&&p.casts==1&&p.updates==1&&!out.HasAura(91262));
AuraEffect own{91262,15};p.effects={&own};m.UpdateWintergraspFlight(&p);assert(p.casts==1&&p.HasAura(91262));
m.permitted=false;m.UpdateWintergraspFlight(&map);assert(!p.HasAura(91262)&&p.updates==2);
m.permitted=true;m.UpdateWintergraspFlight(&map);assert(p.HasAura(91262)&&p.casts==2);
p.area=4538;m.UpdateWintergraspFlight(&p);assert(p.HasAura(91262));
p.area=210;m.UpdateWintergraspFlight(&p);assert(!p.HasAura(91262));
p.area=4197;AuraEffect restriction{91124,13};p.effects={&restriction};m.UpdateWintergraspFlight(&p);assert(!p.HasAura(91262));
AuraEffect permission{86973,15};p.effects={&permission};m.UpdateWintergraspFlight(&p);assert(p.HasAura(91262));
p.effects={&own,&restriction};m.UpdateWintergraspFlight(&p);assert(!p.HasAura(91262));}
'''
with tempfile.TemporaryDirectory(prefix="vcore-wg-client-permission-") as d:
p=Path(d);(p/"test.cpp").write_text(code)
subprocess.run(["c++","-std=c++17",str(p/"test.cpp"),"-o",str(p/"test")],check=True)
subprocess.run([str(p/"test")],check=True)
print("WG permission: entry/subarea/idempotence/battle start/end/exit/aura precedence PASS")
@@ -0,0 +1,25 @@
"""Exercise shared Wintergrasp mount permission with actual manager method."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
s=(root/"src/server/game/Battlefield/BattlefieldMgr.cpp").read_text()
a=s.index("bool BattlefieldMgr::IsWintergraspFlightAllowed(")
b=s.index("\nvoid BattlefieldMgr::UpdateWintergraspFlight",a)
code=r'''
#include <cassert>
#include <vector>
#include <map>
#include <memory>
using uint32=unsigned;
struct DBCManager{static bool IsInArea(unsigned a,unsigned z){return a==z||(z==4197&&a==4538);}};
struct Map{unsigned id=571;unsigned GetId()const{return id;}};
struct Battlefield{bool enabled=true,war=false;unsigned zone=4197;unsigned GetZoneId()const{return zone;}bool IsEnabled()const{return enabled;}bool CanFlyIn()const{return !war;}};
struct BattlefieldMgr{std::map<Map const*,std::vector<std::unique_ptr<Battlefield>>> _battlefieldsByMap;bool IsWintergraspFlightAllowed(uint32,uint32)const;};
'''+s[a:b]+r'''
int main(){BattlefieldMgr m;Map map;assert(m.IsWintergraspFlightAllowed(571,4197));assert(m.IsWintergraspFlightAllowed(571,4538));assert(!m.IsWintergraspFlightAllowed(0,4197));assert(!m.IsWintergraspFlightAllowed(571,210));auto bf=std::make_unique<Battlefield>();auto p=bf.get();m._battlefieldsByMap[&map].push_back(std::move(bf));assert(m.IsWintergraspFlightAllowed(571,4538));p->war=true;assert(!m.IsWintergraspFlightAllowed(571,4197));assert(!m.IsWintergraspFlightAllowed(571,4538));p->enabled=false;assert(m.IsWintergraspFlightAllowed(571,4538));p->enabled=true;p->war=false;assert(m.IsWintergraspFlightAllowed(571,4197));}
'''
with tempfile.TemporaryDirectory(prefix="vcore-wg-flight-") as d:
p=Path(d);(p/"test.cpp").write_text(code)
subprocess.run(["c++","-std=c++17",str(p/"test.cpp"),"-o",str(p/"test")],check=True)
subprocess.run([str(p/"test")],check=True)
print("WG main/subarea: absent, disabled, peace, war, end and unrelated areas PASS")
@@ -0,0 +1,29 @@
"""Run the production flying-area cast check, including explicit aura restrictions."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
s=(root/"src/server/game/Spells/SpellInfo.cpp").read_text()
a=s.index(" // continent limitation (virtual continent)",s.index("SpellInfo::CheckLocation"))
b=s.index(" // raid instance limitation",a)
code=r'''
#include <cassert>
#include <vector>
using uint32=unsigned;
enum class AreaMountFlags{None=0,AllowFlyingMounts=2};
template<class T>struct EnumFlag{int bits;EnumFlag(T v):bits(int(v)){}void operator|=(T v){bits|=int(v);}bool HasFlag(T v){return bits&int(v);}};
constexpr int SPELL_AURA_MOUNT_RESTRICTIONS=1,SPELL_ATTR4_ONLY_FLYING_AREAS=2,SPELL_FAILED_INCORRECT_AREA=3;
struct AuraEffect{int mask;int GetMiscValue()const{return mask;}};
struct Player{bool restrict=false;std::vector<AuraEffect const*> auras;bool HasAuraType(int)const{return restrict;}auto const& GetAuraEffectsByType(int)const{return auras;}};
struct AreaTableEntry{int flags=13;EnumFlag<AreaMountFlags> GetMountFlags()const{return AreaMountFlags(flags);}} area;
struct Areas{AreaTableEntry const* LookupEntry(unsigned){return &area;}} sAreaTableStore;
struct Battlefields{bool war=false;bool IsWintergraspFlightAllowed(unsigned map,unsigned id){return map==571&&(id==4197||id==4538)&&!war;}} battlefield;auto sBattlefieldMgr=&battlefield;
struct SpellInfo{bool HasAttribute(int)const{return true;}int CheckLocation(unsigned map_id,unsigned area_id,Player const* player){
'''+s[a:b]+r'''
return 0;}};
int main(){SpellInfo s;Player p;assert(s.CheckLocation(571,4197,&p)==0);assert(s.CheckLocation(571,4538,&p)==0);battlefield.war=true;assert(s.CheckLocation(571,4538,&p)==SPELL_FAILED_INCORRECT_AREA);battlefield.war=false;assert(s.CheckLocation(571,4538,&p)==0);assert(s.CheckLocation(571,210,&p)==SPELL_FAILED_INCORRECT_AREA);p.restrict=true;AuraEffect noFlight{1};p.auras={&noFlight};assert(s.CheckLocation(571,4197,&p)==SPELL_FAILED_INCORRECT_AREA);AuraEffect flight{3};p.auras={&flight};assert(s.CheckLocation(571,4197,&p)==0);}
'''
with tempfile.TemporaryDirectory(prefix="vcore-wg-mount-cast-") as directory:
p=Path(directory);(p/"test.cpp").write_text(code)
subprocess.run(["c++","-std=c++17",str(p/"test.cpp"),"-o",str(p/"test")],check=True)
subprocess.run([str(p/"test")],check=True)
print("Production mount cast: WG/main/subarea peace/war/end, unrelated zone, aura precedence PASS")
@@ -0,0 +1,40 @@
"""Exercise ZM graveyard ownership with production registration and member setup."""
from pathlib import Path
import subprocess, tempfile
root = Path(__file__).resolve().parents[2]
header = (root / "src/server/scripts/OutdoorPvP/OutdoorPvPZM.h").read_text()
script = (root / "src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp").read_text()
source = (root / "src/server/game/OutdoorPvP/OutdoorPvP.cpp").read_text()
member = next(line for line in header.splitlines() if " m_Graveyard" in line and "State" not in line)
a = script.index(" m_Graveyard =", script.index("bool OutdoorPvPZM::SetupOutdoorPvP"))
b = script.index("\n", script.index("AddCapturePoint(",a))
setup = script[a:b]
a = source.index("void OutdoorPvP::AddCapturePoint(")
b = source.index("\nOPvPCapturePoint* OutdoorPvP::GetCapturePoint",a)
registration = source[a:b]
code = r'''
#include <map>
#include <memory>
#include <cassert>
#define TC_LOG_ERROR(...) ((void)0)
struct OutdoorPvP;
int destroyed=0;
struct OPvPCapturePoint {unsigned m_capturePointSpawnId=0; virtual ~OPvPCapturePoint(){++destroyed;}};
struct OPvPCapturePointZM_Graveyard:OPvPCapturePoint {explicit OPvPCapturePointZM_Graveyard(OutdoorPvP*){}};
struct OutdoorPvP {
using OPvPCapturePointMap=std::map<unsigned,std::unique_ptr<OPvPCapturePoint>>;
OPvPCapturePointMap m_capturePoints;
virtual ~OutdoorPvP()=default;
void AddCapturePoint(OPvPCapturePoint* cp);
};
''' + registration + "struct OutdoorPvPZM: OutdoorPvP {\n" + member + "\nvoid setup(){\n" + setup + r'''
}
};
int main(){for(int i=0;i<100;++i){auto p=std::make_unique<OutdoorPvPZM>();p->setup();assert(p->m_capturePoints.size()==1);assert(p->m_capturePoints.begin()->second.get()==p->m_Graveyard);}assert(destroyed==100);}
'''
with tempfile.TemporaryDirectory(prefix="vcore-zm-ownership-") as directory:
path=Path(directory)
(path/"test.cpp").write_text(code)
subprocess.run(["c++","-std=c++17","-fsanitize=address","-fno-omit-frame-pointer",str(path/"test.cpp"),"-o",str(path/"test")],check=True)
subprocess.run([str(path/"test")],check=True)
print("ZM graveyard: 100 lifecycles, exactly one destruction each, AddressSanitizer PASS")