Core/Loot: Store references to Loot objects directly in players loot view map instead of guids of world objects holding that loot

Port From (https://github.com/TrinityCore/TrinityCore/commit/f19f32f2a49cf0eb235f1aa12106322bf9db2a15)
This commit is contained in:
hondacrx
2022-09-18 15:40:17 -04:00
parent 76dd5b94f0
commit bfdbcd7cbe
4 changed files with 49 additions and 181 deletions
+2 -1
View File
@@ -22,6 +22,7 @@ using Game.Chat;
using Game.DataStorage; using Game.DataStorage;
using Game.Garrisons; using Game.Garrisons;
using Game.Groups; using Game.Groups;
using Game.Loots;
using Game.Mails; using Game.Mails;
using Game.Maps; using Game.Maps;
using Game.Misc; using Game.Misc;
@@ -238,7 +239,7 @@ namespace Game.Entities
SceneMgr m_sceneMgr; SceneMgr m_sceneMgr;
Dictionary<ObjectGuid /*LootObject*/, ObjectGuid /*WorldObject*/> m_AELootView = new(); Dictionary<ObjectGuid, Loot> m_AELootView = new();
CUFProfile[] _CUFProfiles = new CUFProfile[PlayerConst.MaxCUFProfiles]; CUFProfile[] _CUFProfiles = new CUFProfile[PlayerConst.MaxCUFProfiles];
float[] m_powerFraction = new float[(int)PowerType.MaxPerClass]; float[] m_powerFraction = new float[(int)PowerType.MaxPerClass];
+10 -24
View File
@@ -2404,7 +2404,7 @@ namespace Game.Entities
Item bagItem = bag.GetItemByPos(i); Item bagItem = bag.GetItemByPos(i);
if (bagItem != null) if (bagItem != null)
{ {
if (HasLootWorldObjectGUID(bagItem.GetGUID())) if (GetLootByWorldObjectGUID(bagItem.GetGUID()) != null)
{ {
GetSession().DoLootReleaseAll(); GetSession().DoLootReleaseAll();
released = true; // so we don't need to look at dstBag released = true; // so we don't need to look at dstBag
@@ -2422,7 +2422,7 @@ namespace Game.Entities
Item bagItem = bag.GetItemByPos(i); Item bagItem = bag.GetItemByPos(i);
if (bagItem != null) if (bagItem != null)
{ {
if (HasLootWorldObjectGUID(bagItem.GetGUID())) if (GetLootByWorldObjectGUID(bagItem.GetGUID()) != null)
{ {
GetSession().DoLootReleaseAll(); GetSession().DoLootReleaseAll();
break; break;
@@ -4096,25 +4096,12 @@ namespace Game.Entities
} }
} }
public ObjectGuid GetLootWorldObjectGUID(ObjectGuid lootObjectGuid) public Loot GetLootByWorldObjectGUID(ObjectGuid lootWorldObjectGuid)
{ {
if (!m_AELootView.ContainsKey(lootObjectGuid)) if (m_AELootView.TryGetValue(lootWorldObjectGuid, out Loot lootView))
return ObjectGuid.Empty; return lootView;
return m_AELootView[lootObjectGuid]; return null;
}
public void RemoveAELootedWorldObject(ObjectGuid lootWorldObjectGuid)
{
var itr = m_AELootView.FirstOrDefault(pair => pair.Value == lootWorldObjectGuid);
if (itr.Key != ObjectGuid.Empty)
m_AELootView.Remove(itr.Key);
}
public bool HasLootWorldObjectGUID(ObjectGuid lootWorldObjectGuid)
{
return m_AELootView.Any(lootView => lootView.Value == lootWorldObjectGuid);
} }
//Inventory //Inventory
@@ -6073,7 +6060,7 @@ namespace Game.Entities
SendEquipError(msg, null, null, item.itemid); SendEquipError(msg, null, null, item.itemid);
} }
public Dictionary<ObjectGuid, ObjectGuid> GetAELootView() { return m_AELootView; } public Dictionary<ObjectGuid, Loot> GetAELootView() { return m_AELootView; }
/// <summary> /// <summary>
/// if in a Battleground a player dies, and an enemy removes the insignia, the player's bones is lootable /// if in a Battleground a player dies, and an enemy removes the insignia, the player's bones is lootable
@@ -6210,8 +6197,6 @@ namespace Game.Entities
if (lootid != 0) if (lootid != 0)
{ {
loot.Clear();
Group group = GetGroup(); Group group = GetGroup();
bool groupRules = (group && go.GetGoInfo().type == GameObjectTypes.Chest && go.GetGoInfo().Chest.usegrouplootrules != 0); bool groupRules = (group && go.GetGoInfo().type == GameObjectTypes.Chest && go.GetGoInfo().Chest.usegrouplootrules != 0);
@@ -6373,8 +6358,9 @@ namespace Game.Entities
if (creature.CanGeneratePickPocketLoot()) if (creature.CanGeneratePickPocketLoot())
{ {
creature.StartPickPocketRefillTimer(); creature.StartPickPocketRefillTimer();
loot.Clear();
loot = new Loot(GetMap(), creature.GetGUID(), LootType.Pickpocketing);
creature.loot = loot;
uint lootid = creature.GetCreatureTemplate().PickPocketId; uint lootid = creature.GetCreatureTemplate().PickPocketId;
if (lootid != 0) if (lootid != 0)
loot.FillLoot(lootid, LootStorage.Pickpocketing, this, true); loot.FillLoot(lootid, LootStorage.Pickpocketing, this, true);
@@ -6510,7 +6496,7 @@ namespace Game.Entities
// add 'this' player as one of the players that are looting 'loot' // add 'this' player as one of the players that are looting 'loot'
loot.AddLooter(GetGUID()); loot.AddLooter(GetGUID());
m_AELootView[loot.GetGUID()] = guid; m_AELootView[loot.GetGUID()] = loot;
if (loot_type == LootType.Corpse && !guid.IsItem()) if (loot_type == LootType.Corpse && !guid.IsItem())
SetUnitFlag(UnitFlags.Looting); SetUnitFlag(UnitFlags.Looting);
+30 -156
View File
@@ -39,8 +39,14 @@ namespace Game
// @todo Implement looting by LootObject guid // @todo Implement looting by LootObject guid
foreach (LootRequest req in packet.Loot) foreach (LootRequest req in packet.Loot)
{ {
Loot loot = null; Loot loot = player.GetAELootView().LookupByKey(req.Object);
ObjectGuid lguid = player.GetLootWorldObjectGUID(req.Object); if (loot == null)
{
player.SendLootRelease(ObjectGuid.Empty);
continue;
}
ObjectGuid lguid = loot.GetOwnerGUID();
if (lguid.IsGameObject()) if (lguid.IsGameObject())
{ {
@@ -52,33 +58,8 @@ namespace Game
player.SendLootRelease(lguid); player.SendLootRelease(lguid);
continue; continue;
} }
loot = go.GetLootForPlayer(player);
} }
else if (lguid.IsItem()) else if (lguid.IsCreatureOrVehicle())
{
Item pItem = player.GetItemByGuid(lguid);
if (!pItem)
{
player.SendLootRelease(lguid);
continue;
}
loot = pItem.GetLootForPlayer(player);
}
else if (lguid.IsCorpse())
{
Corpse bones = ObjectAccessor.GetCorpse(player, lguid);
if (!bones)
{
player.SendLootRelease(lguid);
continue;
}
loot = bones.GetLootForPlayer(player);
}
else
{ {
Creature creature = player.GetMap().GetCreature(lguid); Creature creature = player.GetMap().GetCreature(lguid);
if (creature == null) if (creature == null)
@@ -92,26 +73,13 @@ namespace Game
player.SendLootError(req.Object, lguid, LootError.TooFar); player.SendLootError(req.Object, lguid, LootError.TooFar);
continue; continue;
} }
loot = creature.GetLootForPlayer(player);
if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing))
{
player.SendLootError(req.Object, lguid, LootError.DidntKill);
continue;
}
}
if (loot == null)
{
player.SendLootRelease(lguid);
continue;
} }
player.StoreLootItem(lguid, (byte)(req.LootListID - 1), loot, aeResult); player.StoreLootItem(lguid, (byte)(req.LootListID - 1), loot, aeResult);
// If player is removing the last LootItem, delete the empty container. // If player is removing the last LootItem, delete the empty container.
if (loot.IsLooted() && lguid.IsItem()) if (loot.IsLooted() && lguid.IsItem())
player.GetSession().DoLootRelease(lguid); player.GetSession().DoLootRelease(loot);
} }
if (aeResult != null) if (aeResult != null)
@@ -135,82 +103,13 @@ namespace Game
foreach (var lootView in player.GetAELootView()) foreach (var lootView in player.GetAELootView())
{ {
ObjectGuid guid = lootView.Value; Loot loot = lootView.Value;
Loot loot = null; ObjectGuid guid = loot.GetOwnerGUID();
bool shareMoney = true; bool shareMoney = loot.loot_type == LootType.Corpse;
switch (guid.GetHigh())
{
case HighGuid.GameObject:
{
GameObject go = player.GetMap().GetGameObject(guid);
// do not check distance for GO if player is the owner of it (ex. fishing bobber)
if (go && (go.GetOwnerGUID() == player.GetGUID() || go.IsWithinDistInMap(player)))
loot = go.GetLootForPlayer(player);
break;
}
case HighGuid.Corpse: // remove insignia ONLY in BG
{
Corpse bones = ObjectAccessor.GetCorpse(player, guid);
if (bones && bones.IsWithinDistInMap(player, SharedConst.InteractionDistance))
{
loot = bones.GetLootForPlayer(player);
shareMoney = false;
}
break;
}
case HighGuid.Item:
{
Item item = player.GetItemByGuid(guid);
if (item)
{
loot = item.GetLootForPlayer(player);
shareMoney = false;
}
break;
}
case HighGuid.Creature:
case HighGuid.Vehicle:
{
Creature creature = player.GetMap().GetCreature(guid);
if (creature == null)
{
player.SendLootError(lootView.Key, guid, LootError.NoLoot);
continue;
}
if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
{
player.SendLootError(lootView.Key, guid, LootError.TooFar);
continue;
}
loot = creature.GetLootForPlayer(player);
if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing))
{
player.SendLootError(lootView.Key, guid, LootError.DidntKill);
continue;
}
if (loot != null && loot.loot_type != LootType.Corpse)
shareMoney = false;
break;
}
default:
continue; // unlootable type
}
if (loot == null)
continue;
loot.NotifyMoneyRemoved(player.GetMap()); loot.NotifyMoneyRemoved(player.GetMap());
if (shareMoney && player.GetGroup() != null) //item, pickpocket and players can be looted only single player if (shareMoney && player.GetGroup() != null) //item, pickpocket and players can be looted only single player
{ {
Group group = player.GetGroup(); Group group = player.GetGroup();
List<Player> playersNear = new(); List<Player> playersNear = new();
@@ -262,7 +161,7 @@ namespace Game
// Delete container if empty // Delete container if empty
if (loot.IsLooted() && guid.IsItem()) if (loot.IsLooted() && guid.IsItem())
player.GetSession().DoLootRelease(guid); player.GetSession().DoLootRelease(loot);
} }
} }
@@ -335,20 +234,21 @@ namespace Game
{ {
// cheaters can modify lguid to prevent correct apply loot release code and re-loot // cheaters can modify lguid to prevent correct apply loot release code and re-loot
// use internal stored guid // use internal stored guid
if (GetPlayer().HasLootWorldObjectGUID(packet.Unit)) Loot loot = GetPlayer().GetLootByWorldObjectGUID(packet.Unit);
DoLootRelease(packet.Unit); if (loot != null)
DoLootRelease(loot);
} }
public void DoLootRelease(ObjectGuid lguid) public void DoLootRelease(Loot loot)
{ {
ObjectGuid lguid = loot.GetOwnerGUID();
Player player = GetPlayer(); Player player = GetPlayer();
Loot loot;
if (player.GetLootGUID() == lguid) if (player.GetLootGUID() == lguid)
player.SetLootGUID(ObjectGuid.Empty); player.SetLootGUID(ObjectGuid.Empty);
player.SendLootRelease(lguid); player.SendLootRelease(lguid);
player.RemoveAELootedWorldObject(lguid); player.GetAELootView().Remove(loot.GetGUID());
if (player.GetAELootView().Empty()) if (player.GetAELootView().Empty())
player.RemoveUnitFlag(UnitFlags.Looting); player.RemoveUnitFlag(UnitFlags.Looting);
@@ -364,8 +264,6 @@ namespace Game
if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player))) if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player)))
return; return;
loot = go.GetLootForPlayer(player);
if (go.GetGoType() == GameObjectTypes.Door) if (go.GetGoType() == GameObjectTypes.Door)
{ {
// locked doors are opened with spelleffect openlock, prevent remove its as looted // locked doors are opened with spelleffect openlock, prevent remove its as looted
@@ -402,11 +300,9 @@ namespace Game
if (!corpse || !corpse.IsWithinDistInMap(player, SharedConst.InteractionDistance)) if (!corpse || !corpse.IsWithinDistInMap(player, SharedConst.InteractionDistance))
return; return;
loot = corpse.GetLootForPlayer(player); if (loot.IsLooted())
if (loot != null && loot.IsLooted())
{ {
loot.Clear(); corpse.loot = null;
corpse.RemoveCorpseDynamicFlag(CorpseDynFlags.Lootable); corpse.RemoveCorpseDynamicFlag(CorpseDynFlags.Lootable);
} }
} }
@@ -418,10 +314,8 @@ namespace Game
ItemTemplate proto = pItem.GetTemplate(); ItemTemplate proto = pItem.GetTemplate();
loot = pItem.GetLootForPlayer(player);
// destroy only 5 items from stack in case prospecting and milling // destroy only 5 items from stack in case prospecting and milling
if (loot != null && (loot.loot_type == LootType.Prospecting || loot.loot_type == LootType.Milling)) if (loot.loot_type == LootType.Prospecting || loot.loot_type == LootType.Milling)
{ {
pItem.m_lootGenerated = false; pItem.m_lootGenerated = false;
pItem.loot = null; pItem.loot = null;
@@ -437,7 +331,7 @@ namespace Game
else else
{ {
// Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item // Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item
if ((loot != null && loot.IsLooted()) || !proto.HasFlag(ItemFlags.HasLoot)) if (loot.IsLooted() || !proto.HasFlag(ItemFlags.HasLoot))
player.DestroyItem(pItem.GetBagSlot(), pItem.GetSlot(), true); player.DestroyItem(pItem.GetBagSlot(), pItem.GetSlot(), true);
} }
return; // item can be looted only single player return; // item can be looted only single player
@@ -451,11 +345,10 @@ namespace Game
if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance)) if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
return; return;
loot = creature.GetLootForPlayer(player);
if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing)) if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing))
return; return;
if (loot == null || loot.IsLooted()) if (loot.IsLooted())
{ {
creature.RemoveDynamicFlag(UnitDynFlags.Lootable); creature.RemoveDynamicFlag(UnitDynFlags.Lootable);
@@ -484,15 +377,14 @@ namespace Game
} }
//Player is not looking at loot list, he doesn't need to see updates on the loot list //Player is not looking at loot list, he doesn't need to see updates on the loot list
if (loot != null) loot.RemoveLooter(player.GetGUID());
loot.RemoveLooter(player.GetGUID());
} }
public void DoLootReleaseAll() public void DoLootReleaseAll()
{ {
Dictionary<ObjectGuid, ObjectGuid> lootView = _player.GetAELootView(); Dictionary<ObjectGuid, Loot> lootView = _player.GetAELootView();
foreach (var lootPair in lootView) foreach (var (_, loot) in lootView)
DoLootRelease(lootPair.Value); DoLootRelease(loot);
} }
[WorldPacketHandler(ClientOpcodes.MasterLootItem)] [WorldPacketHandler(ClientOpcodes.MasterLootItem)]
@@ -516,8 +408,7 @@ namespace Game
foreach (LootRequest req in masterLootItem.Loot) foreach (LootRequest req in masterLootItem.Loot)
{ {
Loot loot = null; Loot loot = _player.GetAELootView().LookupByKey(req.Object);
ObjectGuid lootguid = _player.GetLootWorldObjectGUID(req.Object);
if (!_player.IsInRaidWith(target) || !_player.IsInMap(target)) if (!_player.IsInRaidWith(target) || !_player.IsInMap(target))
{ {
@@ -526,23 +417,6 @@ namespace Game
return; return;
} }
if (GetPlayer().GetLootGUID().IsCreatureOrVehicle())
{
Creature creature = GetPlayer().GetMap().GetCreature(lootguid);
if (!creature)
return;
loot = creature.GetLootForPlayer(_player);
}
else if (GetPlayer().GetLootGUID().IsGameObject())
{
GameObject go = GetPlayer().GetMap().GetGameObject(lootguid);
if (!go)
return;
loot = go.GetLootForPlayer(_player);
}
if (loot == null) if (loot == null)
return; return;
+7
View File
@@ -815,6 +815,13 @@ namespace Game.Loots
PlayerNonQuestNonFFAConditionalItems.Clear(); PlayerNonQuestNonFFAConditionalItems.Clear();
foreach (ObjectGuid playerGuid in PlayersLooting)
{
Player player = Global.ObjAccessor.FindConnectedPlayer(playerGuid);
if (player != null)
player.GetSession().DoLootRelease(this);
}
PlayersLooting.Clear(); PlayersLooting.Clear();
items.Clear(); items.Clear();
quest_items.Clear(); quest_items.Clear();