aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorxinef1 <w.szyszko2@gmail.com>2017-02-04 22:37:16 +0100
committerShauren <shauren.trinity@gmail.com>2017-02-04 22:37:16 +0100
commit86da1a19bb36edf3242dafac6e45e87434ddff73 (patch)
tree5c445d5763a46adbbbfa6d605f40fb8c6ee2f0e6 /src/server/game/Entities
parent9e1b286984c63b801561a67dd4eae7910ec1af10 (diff)
Core/Misc: Fix various crashes, also related to multithreading (#19012)
* When iterating groups we have to either do it not in multithreaded context (map updates) or start with checking maps (they are guaranteed to change in single thread update). * Properly clear ComboPoint references on player remove * remove some possible references item may have when it is deleted during save. * Also clear all hostile references when unit is removed from map.
Diffstat (limited to 'src/server/game/Entities')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp4
-rw-r--r--src/server/game/Entities/Player/KillRewarder.cpp5
-rw-r--r--src/server/game/Entities/Player/Player.cpp32
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Entities/Totem/Totem.cpp2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp16
7 files changed, 38 insertions, 24 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 0d18b915144..3c6fae376fc 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -554,7 +554,7 @@ void Creature::Update(uint32 diff)
{
Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID);
if (group)
- group->EndRoll(&loot);
+ group->EndRoll(&loot, GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID = 0;
}
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 8b80d027c9f..b7f4433b63e 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -582,7 +582,7 @@ void GameObject::Update(uint32 diff)
{
Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID);
if (group)
- group->EndRoll(&loot);
+ group->EndRoll(&loot, GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID = 0;
}
@@ -1290,7 +1290,7 @@ void GameObject::Use(Unit* user)
if (itr->second)
{
- if (Player* ChairUser = ObjectAccessor::FindPlayer(itr->second))
+ if (Player* ChairUser = ObjectAccessor::GetPlayer(*this, itr->second))
{
if (ChairUser->IsSitState() && ChairUser->GetStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->GetStandState() != UNIT_STAND_STATE_SIT check is required.
diff --git a/src/server/game/Entities/Player/KillRewarder.cpp b/src/server/game/Entities/Player/KillRewarder.cpp
index 0235866dbca..61a6277e6cd 100644
--- a/src/server/game/Entities/Player/KillRewarder.cpp
+++ b/src/server/game/Entities/Player/KillRewarder.cpp
@@ -90,7 +90,7 @@ inline void KillRewarder::_InitGroupData()
// 2. In case when player is in group, initialize variables necessary for group calculations:
for (GroupReference* itr = _group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
- if (member->IsAlive() && member->IsAtGroupRewardDistance(_victim))
+ if (_killer == member || (member->IsAtGroupRewardDistance(_victim) && member->IsAlive()))
{
const uint8 lvl = member->getLevel();
// 2.1. _count - number of alive group members within reward distance;
@@ -235,7 +235,8 @@ void KillRewarder::_RewardGroup()
{
if (Player* member = itr->GetSource())
{
- if (member->IsAtGroupRewardDistance(_victim))
+ // Killer may not be at reward distance, check directly
+ if (_killer == member || member->IsAtGroupRewardDistance(_victim))
{
_RewardPlayer(member, isDungeon);
member->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, _victim);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 2edff5f9527..73a20ff0310 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -2145,6 +2145,8 @@ void Player::RemoveFromWorld()
StopCastingCharm();
StopCastingBindSight();
UnsummonPetTemporaryIfAny();
+ ClearComboPoints();
+ ClearComboPointHolders();
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
}
@@ -13467,6 +13469,17 @@ void Player::RemoveEnchantmentDurations(Item* item)
}
}
+void Player::RemoveEnchantmentDurationsReferences(Item* item)
+{
+ for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end();)
+ {
+ if (itr->item == item)
+ itr = m_enchantDuration.erase(itr);
+ else
+ ++itr;
+ }
+}
+
void Player::RemoveArenaEnchantments(EnchantmentSlot slot)
{
// remove enchantments from equipped items first to clean up the m_enchantDuration list
@@ -19605,6 +19618,10 @@ void Player::_SaveInventory(SQLTransaction& trans)
stmt->setUInt32(2, lowGuid);
trans->Append(stmt);
+ RemoveTradeableItem(item);
+ RemoveEnchantmentDurationsReferences(item);
+ RemoveItemDurations(item);
+
// also THIS item should be somewhere else, cheat attempt
item->FSetState(ITEM_REMOVED); // we are IN updateQueue right now, can't use SetState which modifies the queue
DeleteRefundReference(item->GetGUID());
@@ -23631,15 +23648,13 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar
bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
{
- if (!pRewardSource)
+ if (!pRewardSource || !IsInMap(pRewardSource))
return false;
+
const WorldObject* player = GetCorpse();
if (!player || IsAlive())
player = this;
- if (player->GetMapId() != pRewardSource->GetMapId() || player->GetInstanceId() != pRewardSource->GetInstanceId())
- return false;
-
if (player->GetMap()->IsDungeon())
return true;
@@ -23648,15 +23663,13 @@ bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const
{
- if (!pOther)
+ if (!pOther || !IsInMap(pOther))
return false;
+
const WorldObject* player = GetCorpse();
if (!player || IsAlive())
player = this;
- if (player->GetMapId() != pOther->GetMapId() || player->GetInstanceId() != pOther->GetInstanceId())
- return false;
-
return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE);
}
@@ -23909,7 +23922,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid guidMember) const
/// @todo Should also be sent when anyone has recently left combat, with an aprox ~5 seconds timer.
for (GroupReference const* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
- if (itr->GetSource() && itr->GetSource()->IsInCombat())
+ if (itr->GetSource() && itr->GetSource()->IsInMap(this) && itr->GetSource()->IsInCombat())
return ERR_PARTY_LFG_BOOT_IN_COMBAT;
/* Missing support for these types
@@ -25753,7 +25766,6 @@ void Player::ActivateSpec(uint8 spec)
if (Pet* pet = GetPet())
RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
- ClearComboPointHolders();
ClearAllReactives();
UnsummonAllTotems();
ExitVehicle();
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 9e671a305b0..9fbac96b4e6 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1291,6 +1291,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void UpdateItemDuration(uint32 time, bool realtimeonly = false);
void AddEnchantmentDurations(Item* item);
void RemoveEnchantmentDurations(Item* item);
+ void RemoveEnchantmentDurationsReferences(Item* item);
void RemoveArenaEnchantments(EnchantmentSlot slot);
void AddEnchantmentDuration(Item* item, EnchantmentSlot slot, uint32 duration);
void ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool apply_dur = true, bool ignore_condition = false);
diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp
index 65d31fc45dd..74acba5c0a9 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -136,7 +136,7 @@ void Totem::UnSummon(uint32 msTime)
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* target = itr->GetSource();
- if (target && group->SameSubGroup(owner, target))
+ if (target && target->IsInMap(owner) && group->SameSubGroup(owner, target))
target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
}
}
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 3407c63aa38..61cfa0322fd 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -6491,12 +6491,12 @@ Unit* Unit::GetNextRandomRaidMemberOrPet(float radius)
if (Player* Target = itr->GetSource())
{
// IsHostileTo check duel and controlled by enemy
- if (Target != this && Target->IsAlive() && IsWithinDistInMap(Target, radius) && !IsHostileTo(Target))
+ if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
nearMembers.push_back(Target);
// Push player's pet to vector
if (Unit* pet = Target->GetGuardianPet())
- if (pet != this && pet->IsAlive() && IsWithinDistInMap(pet, radius) && !IsHostileTo(pet))
+ if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
nearMembers.push_back(pet);
}
@@ -10371,7 +10371,7 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup)
CombatStop();
ClearComboPointHolders();
DeleteThreatList();
- getHostileRefManager().setOnlineOfflineState(false);
+ getHostileRefManager().deleteReferences();
GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
}
@@ -12555,23 +12555,23 @@ void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
Player* Target = itr->GetSource();
// IsHostileTo check duel and controlled by enemy
- if (Target && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
+ if (Target && Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
{
- if (Target->IsAlive() && IsInMap(Target))
+ if (Target->IsAlive())
TagUnitMap.push_back(Target);
if (Guardian* pet = Target->GetGuardianPet())
- if (pet->IsAlive() && IsInMap(Target))
+ if (pet->IsAlive())
TagUnitMap.push_back(pet);
}
}
}
else
{
- if (owner->IsAlive() && (owner == this || IsInMap(owner)))
+ if ((owner == this || IsInMap(owner)) && owner->IsAlive())
TagUnitMap.push_back(owner);
if (Guardian* pet = owner->GetGuardianPet())
- if (pet->IsAlive() && (pet == this || IsInMap(pet)))
+ if ((pet == this || IsInMap(pet)) && pet->IsAlive())
TagUnitMap.push_back(pet);
}
}