Skip to content

Commit f54adc6

Browse files
H0zenclaude
andauthored
United cores - post fixes (#308)
* Ask for the map instead of asserting on it GetMap() asserts on a NULL map, so `if (GetMap())` is not a guard against an object that never reached one -- it is the crash. Add WorldObject::FindMap(), which returns NULL, and use it in the motion-frame lookup, which is reached from a destructor after LoadFromDB failed. Also ApplyNewEvent, which inserts a game_event_status row that a resumed event already holds: INSERT IGNORE makes it idempotent. Not compiled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Send a boarded player the map his ship sails, not the one he stands on The transfer packet named GetMapId(), which for someone aboard is the vessel's own map. The client has no terrain for that id -- it was never meant to hear of it -- and dies in CMap::LoadWdt() looking for one. It has to be the map she sails, which is the map he is leaving and the one his client is still rendering. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Crashes, pets and extractor --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 2c3bdf6 commit f54adc6

28 files changed

Lines changed: 892 additions & 59 deletions

src/game/ChatCommands/CreatureCommands.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1363,7 +1363,7 @@ namespace
13631363
cellLoaded ? "yes" : "no",
13641364
inWorld ? "" : " (not in world)");
13651365

1366-
if (watched->Where().ShareFrame(unit->Where()))
1366+
if (CanBeSeen(*unit, *watched))
13671367
{
13681368
handler.PSendSysMessage(" distance=%.3f",
13691369
watched->Where().DistanceTo(unit->Where()));

src/game/ChatCommands/DebugCommands.cpp

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
#include "ObjectMgr.h"
5555
#include "ObjectGuid.h"
5656
#include "SpellMgr.h"
57+
#include "Pet.h"
58+
#include "Map.h"
59+
#include "MapManager.h"
60+
#include "TransportMap.h"
61+
#include "Transports.h"
5762

5863
/**
5964
* @brief Handler for HandleDebugSendSpellFailCommand command.
@@ -1789,4 +1794,102 @@ bool ChatHandler::HandleDebugPhaseCommand(char* args)
17891794

17901795
m_session->GetPlayer()->HandleEmoteCommand(emote_id);
17911796
return true;
1792-
}
1797+
}
1798+
/**
1799+
* @brief `.debug minion` -- where a player's minions actually are, deck boundary and all.
1800+
*
1801+
* The steady state is what needs reading, not the transition: a pet left on a deck looks
1802+
* exactly like a pet that followed and stopped, and the difference is a map id. So this
1803+
* reports three things that must agree and usually do not: what the master OWNS, what stands
1804+
* on the master's own map, and what stands on every deck sailing that map.
1805+
*/
1806+
bool ChatHandler::HandleDebugMinionCommand(char* /*args*/)
1807+
{
1808+
Player* master = getSelectedPlayer();
1809+
if (!master)
1810+
{
1811+
master = m_session ? m_session->GetPlayer() : NULL;
1812+
}
1813+
1814+
if (!master)
1815+
{
1816+
SendSysMessage(LANG_NO_CHAR_SELECTED);
1817+
SetSentErrorMessage(true);
1818+
return false;
1819+
}
1820+
1821+
PSendSysMessage("master %s", DescribeSpatially(master).c_str());
1822+
PSendSysMessage("petguid %s transport=%s",
1823+
master->GetPetGuid().GetString().c_str(),
1824+
master->GetTransport() ? "yes" : "no");
1825+
1826+
int owned = 0;
1827+
master->CallForAllControlledUnits(
1828+
[this, &owned](Unit* minion)
1829+
{
1830+
++owned;
1831+
PSendSysMessage("owned %s", DescribeSpatially(minion).c_str());
1832+
},
1833+
CONTROLLED_PET | CONTROLLED_MINIPET | CONTROLLED_GUARDIANS | CONTROLLED_TOTEMS |
1834+
CONTROLLED_CHARM);
1835+
1836+
if (!owned)
1837+
{
1838+
SendSysMessage("owned NONE -- the master controls nothing the sweep can find");
1839+
}
1840+
1841+
Map* on = master->FindMap();
1842+
if (!on)
1843+
{
1844+
return true;
1845+
}
1846+
1847+
DumpPetsOn(on, "onmap");
1848+
1849+
// The decks are the other half of the answer: a pet the master no longer owns is still
1850+
// standing somewhere, and it is almost always on the hull he walked off.
1851+
if (TransportMap* deck = on->AsTransport())
1852+
{
1853+
if (Transport* vessel = deck->Vessel())
1854+
{
1855+
if (Map* sailed = vessel->GetMap())
1856+
{
1857+
DumpPetsOn(sailed, "ashore");
1858+
}
1859+
}
1860+
}
1861+
else
1862+
{
1863+
MapManager::TransportsByMapType::const_iterator vessels =
1864+
sMapMgr.m_TransportsByMap.find(on->GetId());
1865+
if (vessels != sMapMgr.m_TransportsByMap.end())
1866+
{
1867+
for (Transport* vessel : vessels->second)
1868+
{
1869+
if (TransportMap* hull = vessel->AsMap())
1870+
{
1871+
DumpPetsOn(hull, "ondeck");
1872+
}
1873+
}
1874+
}
1875+
}
1876+
1877+
return true;
1878+
}
1879+
1880+
/// Every pet standing on one map, whoever owns it. `label` says which map it was.
1881+
void ChatHandler::DumpPetsOn(Map* on, char const* label)
1882+
{
1883+
for (auto const& entry : on->GetObjectsStore().GetElements<Pet>())
1884+
{
1885+
Pet* pet = entry.second;
1886+
if (!pet)
1887+
{
1888+
continue;
1889+
}
1890+
1891+
Unit* owner = pet->GetOwner();
1892+
PSendSysMessage("%-8s %s owner=%s", label, DescribeSpatially(pet).c_str(),
1893+
owner ? owner->GetGuidStr().c_str() : "(none)");
1894+
}
1895+
}

src/game/MotionGenerators/MotionFrame.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,12 @@ namespace Motion
416416
// The one place in the server where "which world am I in?" is decided. A boarded
417417
// unit moves in its vessel's frame; everything else in the map's. Nothing above
418418
// this call knows the difference, and nothing above it needs to.
419-
if (mover.GetMap() && mover.GetMap()->AsTransport())
419+
if (Map const* on = mover.FindMap())
420420
{
421-
return s_transportFrame;
421+
if (on->AsTransport())
422+
{
423+
return s_transportFrame;
424+
}
422425
}
423426

424427
return s_worldFrame;

src/game/Object/Camera.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ void Camera::SetView(WorldObject* obj, bool update_far_sight_field /*= true*/)
101101
return;
102102
}
103103

104-
if (!m_owner.Where().ShareFrame(obj->Where()))
104+
if (!CanBeSeen(*obj, m_owner))
105105
{
106106
sLog.outError("Camera::SetView, viewpoint is not in map with camera's owner");
107107
return;

src/game/Object/Corpse.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ bool Corpse::LoadFromDB(uint32 lowguid, Field* fields)
321321
*/
322322
bool Corpse::IsVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const
323323
{
324-
return IsInWorld() && u->IsInWorld() && InReach(*this, *viewPoint, GetMap()->GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
324+
return IsInWorld() && u->IsInWorld() && SeenWithin(*this, *viewPoint, GetMap()->GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
325325
}
326326

327327
/**

src/game/Object/DynamicObject.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ bool DynamicObject::IsVisibleForInState(Player const* u, WorldObject const* view
318318
}
319319

320320
// normal case
321-
return InReach(*this, *viewPoint, GetMap()->GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
321+
return SeenWithin(*this, *viewPoint, GetMap()->GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
322322
}
323323

324324
/**

src/game/Object/GameObject.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ bool GameObject::IsVisibleForInState(Player const* u, WorldObject const* viewPoi
679679
}
680680

681681
// Transport always visible at this step implementation
682-
if (IsTransport() && Where().ShareFrame(u->Where()))
682+
if (IsTransport() && CanBeSeen(*this, *u))
683683
{
684684
return true;
685685
}
@@ -747,7 +747,7 @@ bool GameObject::IsVisibleForInState(Player const* u, WorldObject const* viewPoi
747747
}
748748

749749
// check distance
750-
return InReach(*this, *viewPoint, GetMap()->GetVisibilityDistance() +
750+
return SeenWithin(*this, *viewPoint, GetMap()->GetVisibilityDistance() +
751751
(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
752752
}
753753

src/game/Object/Object.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,11 @@ class WorldObject : public Object
765765

766766
void SetMap(Map* map);
767767
Map* GetMap() const { MANGOS_ASSERT(m_currMap); return m_currMap; }
768+
769+
/// The map, or NULL, for the paths that legitimately run on an object which never
770+
/// reached one -- a destructor after LoadFromDB failed, above all. GetMap() asserts
771+
/// there, so `if (GetMap())` is not a guard, it is the crash.
772+
Map* FindMap() const { return m_currMap; }
768773
// used to check all object's GetMap() calls when object is not in world!
769774
void ResetMap();
770775

src/game/Object/Pet.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <algorithm>
2828
#include <string>
2929
#include "Pet.h"
30+
#include "TransportMap.h"
3031
#include "Database/DatabaseEnv.h"
3132
#include "Log.h"
3233
#include "WorldPacket.h"
@@ -164,8 +165,17 @@ void Pet::Update(uint32 update_diff, uint32 diff)
164165
{
165166
// unsummon pet that lost owner
166167
Unit* owner = GetOwner();
168+
// A minion whose master is on ANOTHER MAP is mid-crossing, not off its leash.
169+
// Stepping on or off a deck leaves them in different frames for the one tick
170+
// before TransportMap's reconciler draws it across, and InReach fails closed on
171+
// a cross-frame question. Unsummoning on that answer is how a pet vanished the
172+
// instant its master went ashore.
173+
const bool crossingDeck = owner && !Where().ShareFrame(owner->Where()) &&
174+
((FindMap() && FindMap()->AsTransport()) ||
175+
(owner->FindMap() && owner->FindMap()->AsTransport()));
176+
167177
if (!owner ||
168-
(!InReach(*this, *owner, GetMap()->GetVisibilityDistance()) && (owner->GetCharmGuid() && (owner->GetCharmGuid() != GetObjectGuid()))) ||
178+
(!crossingDeck && !InReach(*this, *owner, GetMap()->GetVisibilityDistance()) && (owner->GetCharmGuid() && (owner->GetCharmGuid() != GetObjectGuid()))) ||
169179
(isControlled() && !owner->GetPetGuid()))
170180
{
171181
Unsummon(PET_SAVE_REAGENTS);

src/game/Object/Player.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1904,7 +1904,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
19041904
if (m_transport)
19051905
{
19061906
data.WriteBit(1); // has transport
1907-
data << uint32(GetMapId());
1907+
// The map he is LEAVING, and that is the one the ship sails. Never her
1908+
// own: the client has no terrain for it and dies in CMap::LoadWdt().
1909+
data << uint32(m_transport->GetMapId());
19081910
data << uint32(m_transport->GetEntry());
19091911
}
19101912
else

0 commit comments

Comments
 (0)