diff --git a/src/aoe_loot.cpp b/src/aoe_loot.cpp index 5ae4774..a79db3a 100644 --- a/src/aoe_loot.cpp +++ b/src/aoe_loot.cpp @@ -16,87 +16,189 @@ */ #include "aoe_loot.h" +#include +#include void AOELootPlayer::OnPlayerLogin(Player* player) { + if (!player) + return; + if (sConfigMgr->GetOption("AOELoot.Enable", true)) { if (sConfigMgr->GetOption("AOELoot.Message", true)) - ChatHandler(player->GetSession()).PSendSysMessage(AOE_ACORE_STRING_MESSAGE); + { + if (WorldSession* session = player->GetSession()) + { + ChatHandler(session).PSendSysMessage(AOE_ACORE_STRING_MESSAGE); + } + } } } bool AOELootServer::CanPacketReceive(WorldSession* session, WorldPacket& packet) { - if (packet.GetOpcode() == CMSG_LOOT) - { - Player* player = session->GetPlayer(); + // Only handle loot packets + if (packet.GetOpcode() != CMSG_LOOT) + return true; - if (!sConfigMgr->GetOption("AOELoot.Enable", true)) - return true; + // Basic validation checks + if (!session) + return true; - if (player->GetGroup() && !sConfigMgr->GetOption("AOELoot.Group", true)) - return true; + Player* player = session->GetPlayer(); + if (!player) + return true; - float range = sConfigMgr->GetOption("AOELoot.Range", 55.0); + // Check if module is enabled + if (!sConfigMgr->GetOption("AOELoot.Enable", true)) + return true; - std::list lootcreature; player->GetDeadCreatureListInGrid(lootcreature, range); + // Check group settings + if (player->GetGroup() && !sConfigMgr->GetOption("AOELoot.Group", true)) + return true; - ObjectGuid guid; packet >> guid; + // Get configured loot range + float range = sConfigMgr->GetOption("AOELoot.Range", 30.0f); - Loot* mainloot = &(player->GetMap()->GetCreature(guid))->loot; + // Limit range to reasonable values + if (range < 5.0f) + range = 5.0f; + if (range > 100.0f) + range = 100.0f; - for (auto itr = lootcreature.begin(); itr != lootcreature.end(); ++itr) + // Read target GUID from packet + ObjectGuid targetGuid; + packet >> targetGuid; + + if (!targetGuid) + return true; + + // Get target creature + Creature* mainCreature = player->GetMap()->GetCreature(targetGuid); + if (!mainCreature) + return true; + + // Check if main creature has loot + if (!mainCreature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE)) + return true; + + // Get nearby corpses + std::list nearbyCorpses; + player->GetDeadCreatureListInGrid(nearbyCorpses, range); + + // Remove invalid corpses and main target + nearbyCorpses.remove_if([&](Creature* c) { - Creature* creature = *itr; + return !c || + c->GetGUID() == targetGuid || + !c->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE) || + !player->isAllowedToLoot(c); + }); - // Prevent infiny add items - if (creature->GetGUID() == guid) - continue; - - // Prevent steal loot - if (!player->GetMap()->Instanceable()) - if (!player->isAllowedToLoot(creature)) - continue; - - // Max 15 items per creature - if (mainloot->items.size() + mainloot->quest_items.size() > 15) - break; - - Loot* loot = &(*itr)->loot; - - // FILL QITEMS - if (!loot->quest_items.empty()) - { - mainloot->items.insert(mainloot->items.end(), loot->quest_items.begin(), loot->quest_items.end()); - loot->quest_items.clear(); - } - - // FILL GOLD - if (loot->gold != 0) - { - mainloot->gold += loot->gold; - loot->gold = 0; - } - - // FILL ITEMS - if (!loot->items.empty()) - { - mainloot->items.insert(mainloot->items.end(), loot->items.begin(), loot->items.end()); - loot->items.clear(); - } - - // Set flag for skinning - if (loot->items.empty() && loot->quest_items.empty()) - { - creature->AllLootRemovedFromCorpse(); - creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE); - } - } - - player->SendLoot(guid, LOOT_CORPSE); + // If no other corpses, process normally + if (nearbyCorpses.empty()) + { + player->SendLoot(targetGuid, LOOT_CORPSE); return false; } - return true; + // Get main loot + Loot* mainLoot = &mainCreature->loot; + + // Limit number of corpses to process + const size_t maxCorpses = 10; // 减少到10个以提高稳定性 + size_t processedCorpses = 0; + + // Track total gold to merge + uint32 totalGold = mainLoot->gold; + + // Collect all items to merge (don't modify main loot directly) + std::vector itemsToAdd; + std::vector questItemsToAdd; + + for (Creature* creature : nearbyCorpses) + { + if (processedCorpses >= maxCorpses) + break; + + if (!creature) + continue; + + Loot* loot = &creature->loot; + + // Skip already looted corpses + if (loot->isLooted()) + continue; + + // Collect gold + if (loot->gold > 0) + { + // Prevent overflow + if (totalGold < std::numeric_limits::max() - loot->gold) + { + totalGold += loot->gold; + } + } + + // Collect regular items + for (size_t i = 0; i < loot->items.size(); ++i) + { + // Check if there's still space + if (mainLoot->items.size() + itemsToAdd.size() + + mainLoot->quest_items.size() + questItemsToAdd.size() >= 15) + { + break; + } + + itemsToAdd.push_back(loot->items[i]); + } + + // Collect quest items + for (size_t i = 0; i < loot->quest_items.size(); ++i) + { + // Check if there's still space + if (mainLoot->items.size() + itemsToAdd.size() + + mainLoot->quest_items.size() + questItemsToAdd.size() >= 15) + { + break; + } + + questItemsToAdd.push_back(loot->quest_items[i]); + } + + // Clear source loot (but don't modify vector directly) + loot->clear(); + creature->AllLootRemovedFromCorpse(); + creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE); + + processedCorpses++; + } + + // Now safely add collected items to main loot + // Update gold + mainLoot->gold = totalGold; + + // Add regular items + for (const auto& item : itemsToAdd) + { + if (mainLoot->items.size() < 15) + { + mainLoot->items.push_back(item); + } + } + + // Add quest items + for (const auto& item : questItemsToAdd) + { + if (mainLoot->quest_items.size() < 15) + { + mainLoot->quest_items.push_back(item); + } + } + + // Send merged loot window + player->SendLoot(targetGuid, LOOT_CORPSE); + + return false; }