Core/Misc: Fix various crashes, also related to multithreading

Port From (https://github.com/TrinityCore/TrinityCore/commit/ad008c43b75080ec59aa973f1e2e4424332c34a4)
This commit is contained in:
hondacrx
2019-08-16 22:03:02 -04:00
parent 653a9bb035
commit d3bce6a75c
19 changed files with 174 additions and 117 deletions
+4 -4
View File
@@ -271,14 +271,14 @@ namespace Game.AI
{
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player Target = refe.GetSource();
if (!Target || !group.SameSubGroup(owner.ToPlayer(), Target))
Player target = refe.GetSource();
if (!target || !target.IsInMap(owner) || !group.SameSubGroup(owner.ToPlayer(), target))
continue;
if (Target.GetGUID() == owner.GetGUID())
if (target.GetGUID() == owner.GetGUID())
continue;
m_AllySet.Add(Target.GetGUID());
m_AllySet.Add(target.GetGUID());
}
}
else //remove group
@@ -115,7 +115,8 @@ namespace Game.AI
{
Player member = groupRef.GetSource();
if (member)
member.FailQuest(m_pQuestForEscort.Id);
if (member.IsInMap(player))
member.FailQuest(m_pQuestForEscort.Id);
}
}
else
@@ -153,7 +153,8 @@ namespace Game.AI
{
Player member = groupRef.GetSource();
if (member)
member.FailQuest(m_pQuestForFollow.Id);
if (member.IsInMap(player))
member.FailQuest(m_pQuestForFollow.Id);
}
}
else
@@ -343,8 +344,7 @@ namespace Game.AI
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
{
Player member = groupRef.GetSource();
if (member && member.IsAlive() && me.IsWithinDistInMap(member, 100.0f))
if (member && me.IsWithinDistInMap(member, 100.0f) && member.IsAlive())
{
Log.outDebug(LogFilter.Scripts, "FollowerAI GetLeader changed and returned new leader.");
m_uiLeaderGUID = member.GetGUID();
+3 -2
View File
@@ -249,6 +249,8 @@ namespace Game.AI
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
{
Player groupGuy = groupRef.GetSource();
if (!groupGuy.IsInMap(player))
continue;
if (!fail && groupGuy.IsAtGroupRewardDistance(me) && !groupGuy.GetCorpse())
groupGuy.AreaExploredOrEventHappens(mEscortQuestID);
@@ -402,8 +404,7 @@ namespace Game.AI
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
{
Player groupGuy = groupRef.GetSource();
if (me.GetDistance(groupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST)
if (groupGuy.IsInMap(player) && me.GetDistance(groupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST)
return true;
}
}
+4 -2
View File
@@ -2614,7 +2614,8 @@ namespace Game.AI
{
Player member = groupRef.GetSource();
if (member)
l.Add(member);
if (member.IsInMap(player))
l.Add(member);
}
}
// We still add the player to the list if there is no group. If we do
@@ -2838,7 +2839,8 @@ namespace Game.AI
{
Player recipient = refe.GetSource();
if (recipient)
l.Add(recipient);
if (recipient.IsInMap(me))
l.Add(recipient);
}
}
else
+4
View File
@@ -239,6 +239,10 @@ namespace Game.Combat
{
return threatContainer.empty();
}
public bool areThreatListsEmpty()
{
return threatContainer.empty() && threatOfflineContainer.empty();
}
public HostileReference getCurrentVictim()
{
+2 -1
View File
@@ -400,7 +400,8 @@ namespace Game.Entities
{
Group group = Global.GroupMgr.GetGroupByGUID(lootingGroupLowGUID);
if (group)
group.EndRoll(loot);
group.EndRoll(loot, GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID.Clear();
}
@@ -668,7 +668,7 @@ namespace Game.Entities
{
Group group = Global.GroupMgr.GetGroupByGUID(lootingGroupLowGUID);
if (group)
group.EndRoll(loot);
group.EndRoll(loot, GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID.Clear();
@@ -1396,7 +1396,7 @@ namespace Game.Entities
if (!slot.Value.IsEmpty())
{
Player ChairUser = Global.ObjAccessor.FindPlayer(slot.Value);
Player ChairUser = Global.ObjAccessor.GetPlayer(this, slot.Value);
if (ChairUser != null)
if (ChairUser.IsSitState() && ChairUser.GetStandState() != UnitStandStateType.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.
+3 -2
View File
@@ -104,7 +104,7 @@ namespace Game.Entities
Player member = refe.GetSource();
if (member)
{
if (member.IsAlive() && member.IsAtGroupRewardDistance(_victim))
if (_killer == member || (member.IsAtGroupRewardDistance(_victim) && member.IsAlive()))
{
uint lvl = member.getLevel();
// 2.1. _count - number of alive group members within reward distance;
@@ -254,7 +254,8 @@ namespace Game.Entities
Player member = refe.GetSource();
if (member)
{
if (member.IsAtGroupRewardDistance(_victim))
// Killer may not be at reward distance, check directly
if (_killer == member || member.IsAtGroupRewardDistance(_victim))
{
_RewardPlayer(member, isDungeon);
member.UpdateCriteria(CriteriaTypes.SpecialPvpKill, 1, 0, 0, _victim);
+4
View File
@@ -1525,6 +1525,10 @@ namespace Game.Entities
stmt.AddValue(2, GetGUID().GetCounter());
trans.Append(stmt);
RemoveTradeableItem(item);
RemoveEnchantmentDurationsReferences(item);
RemoveItemDurations(item);
// also THIS item should be somewhere else, cheat attempt
item.FSetState(ItemUpdateState.Removed); // we are IN updateQueue right now, can't use SetState which modifies the queue
DeleteRefundReference(item.GetGUID());
+3 -5
View File
@@ -76,7 +76,7 @@ namespace Game.Entities
// @todo Should also be sent when anyone has recently left combat, with an aprox ~5 seconds timer.
for (GroupReference refe = grp.GetFirstMember(); refe != null; refe = refe.next())
if (refe.GetSource() && refe.GetSource().IsInCombat())
if (refe.GetSource() && refe.GetSource().IsInMap(this) && refe.GetSource().IsInCombat())
return PartyResult.PartyLfgBootInCombat;
/* Missing support for these types
@@ -192,15 +192,13 @@ namespace Game.Entities
public bool IsAtGroupRewardDistance(WorldObject pRewardSource)
{
if (!pRewardSource)
if (!pRewardSource || !IsInMap(pRewardSource))
return false;
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;
+16 -1
View File
@@ -967,6 +967,16 @@ namespace Game.Entities
}
}
}
void RemoveEnchantmentDurationsReferences(Item item)
{
foreach (var enchantDuration in m_enchantDuration)
{
if (enchantDuration.item == item)
m_enchantDuration.Remove(enchantDuration);
}
}
public void RemoveArenaEnchantments(EnchantmentSlot slot)
{
// remove enchantments from equipped items first to clean up the m_enchantDuration list
@@ -1043,7 +1053,12 @@ namespace Game.Entities
}
// from spell cases (m_lastPotionId set in Spell.SendSpellCooldown)
else
GetSpellHistory().SendCooldownEvent(spell.m_spellInfo, m_lastPotionId, spell);
{
if (spell.IsIgnoringCooldowns())
return;
else
GetSpellHistory().SendCooldownEvent(spell.m_spellInfo, m_lastPotionId, spell);
}
m_lastPotionId = 0;
}
+3 -4
View File
@@ -862,6 +862,7 @@ namespace Game.Entities
StopCastingCharm();
StopCastingBindSight();
UnsummonPetTemporaryIfAny();
ClearComboPoints();
Global.OutdoorPvPMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId);
Global.BattleFieldMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId);
}
@@ -7031,15 +7032,13 @@ namespace Game.Entities
bool IsAtRecruitAFriendDistance(WorldObject pOther)
{
if (!pOther)
if (!pOther || !IsInMap(pOther))
return false;
WorldObject player = GetCorpse();
if (!player || IsAlive())
player = this;
if (player.GetMapId() != pOther.GetMapId() || player.GetInstanceId() != pOther.GetInstanceId())
return false;
return pOther.GetDistance(player) <= WorldConfig.GetFloatValue(WorldCfg.MaxRecruitAFriendDistance);
}
+1 -1
View File
@@ -135,7 +135,7 @@ namespace Game.Entities
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player target = refe.GetSource();
if (target && group.SameSubGroup(owner, target))
if (target && target.IsInMap(owner) && group.SameSubGroup(owner, target))
target.RemoveAurasDueToSpell(GetSpell(), GetGUID());
}
}
+6 -6
View File
@@ -1741,17 +1741,17 @@ namespace Game.Entities
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player Target = refe.GetSource();
if (Target)
Player target = refe.GetSource();
if (target)
{
// IsHostileTo check duel and controlled by enemy
if (Target != this && Target.IsAlive() && IsWithinDistInMap(Target, radius) && !IsHostileTo(Target))
nearMembers.Add(Target);
if (target != this && IsWithinDistInMap(target, radius) && target.IsAlive() && !IsHostileTo(target))
nearMembers.Add(target);
// Push player's pet to vector
Unit pet = Target.GetGuardianPet();
Unit pet = target.GetGuardianPet();
if (pet)
if (pet != this && pet.IsAlive() && IsWithinDistInMap(pet, radius) && !IsHostileTo(pet))
if (pet != this && IsWithinDistInMap(pet, radius) && pet.IsAlive() && !IsHostileTo(pet))
nearMembers.Add(pet);
}
}
+1 -1
View File
@@ -485,7 +485,7 @@ namespace Game.Entities
m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map.RemoveAllObjectsInRemoveList
CombatStop();
DeleteThreatList();
getHostileRefManager().setOnlineOfflineState(false);
getHostileRefManager().deleteReferences();
GetMotionMaster().Clear(false); // remove different non-standard movement generators.
}
public override void CleanupsBeforeDelete(bool finalCleanup = true)
+110 -80
View File
@@ -560,7 +560,7 @@ namespace Game.Groups
roll.playerVote.Remove(guid);
if (roll.totalPass + roll.totalNeed + roll.totalGreed >= roll.totalPlayersRolling)
CountTheRoll(roll);
CountTheRoll(roll, null);
}
// Update subgroups
@@ -1110,21 +1110,21 @@ namespace Game.Groups
}
if (roll.totalPass + roll.totalNeed + roll.totalGreed >= roll.totalPlayersRolling)
CountTheRoll(roll);
CountTheRoll(roll, null);
}
public void EndRoll(Loot pLoot)
public void EndRoll(Loot pLoot, Map allowedMap)
{
foreach (var roll in RollId)
{
if (roll.getLoot() == pLoot)
{
CountTheRoll(roll); //i don't have to edit player votes, who didn't vote ... he will pass
CountTheRoll(roll, allowedMap); //i don't have to edit player votes, who didn't vote ... he will pass
}
}
}
void CountTheRoll(Roll roll)
void CountTheRoll(Roll roll, Map allowedMap)
{
if (!roll.isValid()) // is loot already deleted ?
{
@@ -1138,13 +1138,21 @@ namespace Game.Groups
if (!roll.playerVote.Empty())
{
byte maxresul = 0;
ObjectGuid maxguid = roll.playerVote.First().Key;
ObjectGuid maxguid = ObjectGuid.Empty;
Player player = null;
foreach (var pair in roll.playerVote)
{
if (pair.Value != RollType.Need)
continue;
player = Global.ObjAccessor.FindPlayer(pair.Key);
if (!player || (allowedMap != null && player.GetMap() != allowedMap))
{
--roll.totalNeed;
continue;
}
byte randomN = (byte)RandomHelper.IRand(1, 100);
SendLootRoll(pair.Key, randomN, RollType.Need, roll);
if (maxresul < randomN)
@@ -1153,66 +1161,18 @@ namespace Game.Groups
maxresul = randomN;
}
}
SendLootRollWon(maxguid, maxresul, RollType.Need, roll);
Player player = Global.ObjAccessor.FindPlayer(maxguid);
if (player && player.GetSession() != null)
if (!maxguid.IsEmpty())
{
player.UpdateCriteria(CriteriaTypes.RollNeedOnLoot, roll.itemid, maxresul);
SendLootRollWon(maxguid, maxresul, RollType.Need, roll);
player = Global.ObjAccessor.FindConnectedPlayer(maxguid);
List<ItemPosCount> dest = new List<ItemPosCount>();
LootItem item = (roll.itemSlot >= roll.getLoot().items.Count ? roll.getLoot().quest_items[roll.itemSlot - roll.getLoot().items.Count] : roll.getLoot().items[roll.itemSlot]);
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, roll.itemid, item.count);
if (msg == InventoryResult.Ok)
if (player && player.GetSession())
{
item.is_looted = true;
roll.getLoot().NotifyItemRemoved(roll.itemSlot);
roll.getLoot().unlootedCount--;
player.StoreNewItem(dest, roll.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context, item.BonusListIDs);
}
else
{
item.is_blocked = false;
item.rollWinnerGUID = player.GetGUID();
player.SendEquipError(msg, null, null, roll.itemid);
}
}
}
}
else if (roll.totalGreed > 0)
{
if (!roll.playerVote.Empty())
{
byte maxresul = 0;
ObjectGuid maxguid = roll.playerVote.First().Key;
RollType rollVote = RollType.NotValid;
player.UpdateCriteria(CriteriaTypes.RollNeedOnLoot, roll.itemid, maxresul);
foreach (var pair in roll.playerVote)
{
if (pair.Value != RollType.Greed && pair.Value != RollType.Disenchant)
continue;
byte randomN = (byte)RandomHelper.IRand(1, 100);
SendLootRoll(pair.Key, randomN, pair.Value, roll);
if (maxresul < randomN)
{
maxguid = pair.Key;
maxresul = randomN;
rollVote = pair.Value;
}
}
SendLootRollWon(maxguid, maxresul, rollVote, roll);
Player player = Global.ObjAccessor.FindPlayer(maxguid);
if (player && player.GetSession() != null)
{
player.UpdateCriteria(CriteriaTypes.RollGreedOnLoot, roll.itemid, maxresul);
LootItem item = roll.itemSlot >= roll.getLoot().items.Count ? roll.getLoot().quest_items[roll.itemSlot - roll.getLoot().items.Count] : roll.getLoot().items[roll.itemSlot];
if (rollVote == RollType.Greed)
{
List<ItemPosCount> dest = new List<ItemPosCount>();
LootItem item = (roll.itemSlot >= roll.getLoot().items.Count ? roll.getLoot().quest_items[roll.itemSlot - roll.getLoot().items.Count] : roll.getLoot().items[roll.itemSlot]);
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, roll.itemid, item.count);
if (msg == InventoryResult.Ok)
{
@@ -1228,37 +1188,107 @@ namespace Game.Groups
player.SendEquipError(msg, null, null, roll.itemid);
}
}
else if (rollVote == RollType.Disenchant)
}
else
roll.totalNeed = 0;
}
}
if (roll.totalNeed == 0 && roll.totalGreed > 0) // if (roll->totalNeed == 0 && ...), not else if, because numbers can be modified above if player is on a different map
{
if (!roll.playerVote.Empty())
{
byte maxresul = 0;
ObjectGuid maxguid = ObjectGuid.Empty;
Player player = null;
RollType rollVote = RollType.NotValid;
foreach (var pair in roll.playerVote)
{
if (pair.Value != RollType.Greed && pair.Value != RollType.Disenchant)
continue;
player = Global.ObjAccessor.FindPlayer(pair.Key);
if (!player || (allowedMap != null && player.GetMap() != allowedMap))
{
item.is_looted = true;
roll.getLoot().NotifyItemRemoved(roll.itemSlot);
roll.getLoot().unlootedCount--;
player.UpdateCriteria(CriteriaTypes.CastSpell, 13262); // Disenchant
--roll.totalGreed;
continue;
}
ItemDisenchantLootRecord disenchant = roll.GetItemDisenchantLoot(player);
byte randomN = (byte)RandomHelper.IRand(1, 100);
SendLootRoll(pair.Key, randomN, pair.Value, roll);
if (maxresul < randomN)
{
maxguid = pair.Key;
maxresul = randomN;
rollVote = pair.Value;
}
}
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, roll.itemid, item.count);
if (msg == InventoryResult.Ok)
player.AutoStoreLoot(disenchant.Id, LootStorage.Disenchant, true);
else // If the player's inventory is full, send the disenchant result in a mail.
if (!maxguid.IsEmpty())
{
SendLootRollWon(maxguid, maxresul, rollVote, roll);
player = Global.ObjAccessor.FindConnectedPlayer(maxguid);
if (player && player.GetSession() != null)
{
player.UpdateCriteria(CriteriaTypes.RollGreedOnLoot, roll.itemid, maxresul);
LootItem item = roll.itemSlot >= roll.getLoot().items.Count ? roll.getLoot().quest_items[roll.itemSlot - roll.getLoot().items.Count] : roll.getLoot().items[roll.itemSlot];
if (rollVote == RollType.Greed)
{
Loot loot = new Loot();
loot.FillLoot(disenchant.Id, LootStorage.Disenchant, player, true);
uint max_slot = loot.GetMaxSlotInLootFor(player);
for (uint i = 0; i < max_slot; ++i)
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, roll.itemid, item.count);
if (msg == InventoryResult.Ok)
{
LootItem lootItem = loot.LootItemInSlot(i, player);
player.SendEquipError(msg, null, null, lootItem.itemid);
player.SendItemRetrievalMail(lootItem.itemid, lootItem.count);
item.is_looted = true;
roll.getLoot().NotifyItemRemoved(roll.itemSlot);
roll.getLoot().unlootedCount--;
player.StoreNewItem(dest, roll.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context, item.BonusListIDs);
}
else
{
item.is_blocked = false;
item.rollWinnerGUID = player.GetGUID();
player.SendEquipError(msg, null, null, roll.itemid);
}
}
else if (rollVote == RollType.Disenchant)
{
item.is_looted = true;
roll.getLoot().NotifyItemRemoved(roll.itemSlot);
roll.getLoot().unlootedCount--;
player.UpdateCriteria(CriteriaTypes.CastSpell, 13262); // Disenchant
ItemDisenchantLootRecord disenchant = roll.GetItemDisenchantLoot(player);
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, roll.itemid, item.count);
if (msg == InventoryResult.Ok)
player.AutoStoreLoot(disenchant.Id, LootStorage.Disenchant, true);
else // If the player's inventory is full, send the disenchant result in a mail.
{
Loot loot = new Loot();
loot.FillLoot(disenchant.Id, LootStorage.Disenchant, player, true);
uint max_slot = loot.GetMaxSlotInLootFor(player);
for (uint i = 0; i < max_slot; ++i)
{
LootItem lootItem = loot.LootItemInSlot(i, player);
player.SendEquipError(msg, null, null, lootItem.itemid);
player.SendItemRetrievalMail(lootItem.itemid, lootItem.count);
}
}
}
}
}
else
roll.totalGreed = 0;
}
}
else
if (roll.totalNeed == 0 && roll.totalGreed == 0) // if, not else, because numbers can be modified above if player is on a different map
{
SendLootAllPassed(roll);
+2 -1
View File
@@ -228,7 +228,8 @@ namespace Game.Loots
{
Player player = refe.GetSource();
if (player) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
FillNotNormalLootFor(player, player.IsAtGroupRewardDistance(lootOwner));
if (player.IsInMap(lootOwner))
FillNotNormalLootFor(player, player.IsAtGroupRewardDistance(lootOwner));
}
for (byte i = 0; i < items.Count; ++i)
+1 -1
View File
@@ -167,7 +167,7 @@ namespace Game.Maps
creature.RemoveAllDynObjects();
creature.RemoveAllAreaTriggers();
if (creature.IsInCombat())
if (creature.IsInCombat() || !creature.GetThreatManager().areThreatListsEmpty())
{
creature.CombatStop();
creature.DeleteThreatList();