diff options
| author | xinef1 <w.szyszko2@gmail.com> | 2017-02-04 22:37:16 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2017-02-04 22:37:16 +0100 |
| commit | 86da1a19bb36edf3242dafac6e45e87434ddff73 (patch) | |
| tree | 5c445d5763a46adbbbfa6d605f40fb8c6ee2f0e6 /src/server/game/Entities | |
| parent | 9e1b286984c63b801561a67dd4eae7910ec1af10 (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.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/KillRewarder.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 32 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/Totem/Totem.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 16 |
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); } } |
