rendered paste bodyIndex: configure.ac===================================================================--- configure.ac (revision 4909)+++ configure.ac (working copy)@@ -228,7 +228,9 @@ src/mangosd/Makefile src/mangosd/mangosd.conf src/bindings/Makefile- src/bindings/universal/Makefile+ src/bindings/ScriptDev2/Makefile+ src/bindings/ScriptDev2/sql/Makefile+ src/bindings/ScriptDev2/sql/Updates/Makefile ]) ## Disabled Makefiles, until they are ready for a successful make andIndex: src/bindings/Makefile.am===================================================================--- src/bindings/Makefile.am (revision 4909)+++ src/bindings/Makefile.am (working copy)@@ -14,4 +14,4 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -SUBDIRS = universal+SUBDIRS = ScriptDev2Index: src/game/BattleGroundMgr.cpp===================================================================--- src/game/BattleGroundMgr.cpp (revision 4909)+++ src/game/BattleGroundMgr.cpp (working copy)@@ -79,10 +79,34 @@ else m_QueuedPlayers[queue_id].Horde++; - /* temporary BG queue status message - std::ostringstream str;- str << "Battleground queue invited status: horde: " << m_QueuedPlayers[queue_id].Horde << ", aliance: " << m_QueuedPlayers[queue_id].Alliance;- plr->Say(str.str(), LANG_UNIVERSAL);*/+ /* temporary BG queue status message */+ //#TODO: add proper check for the number of players in queue+ if ( m_QueuedPlayers[queue_id].Alliance == 5 || m_QueuedPlayers[queue_id].Alliance == 7 || m_QueuedPlayers[queue_id].Alliance == 10 ||+ m_QueuedPlayers[queue_id].Horde == 5 || m_QueuedPlayers[queue_id].Horde == 7 || m_QueuedPlayers[queue_id].Horde == 10 )+ {+ std::ostringstream str;+ str << "Battleground queue invited status for ";+ switch (bgTypeId)+ {+ case 1:+ str << "Alterac Valley"; break;+ case 2:+ str << "Warsong Gulch"; break;+ case 3:+ str << "Arathi Basin"; break;+ //#TODO: add other cases+ default:+ str << "other bg / arena"; break;+ }+ str << ", for level ";+ if(plr->getLevel()!=sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))+ str << (int)(plr->getLevel()/10)*10 << " - " << (int)(plr->getLevel()/10)*10+9;+ else+ str << plr->getLevel(); + str << ":\n Horde: " << m_QueuedPlayers[queue_id].Horde << ", Alliance: " << m_QueuedPlayers[queue_id].Alliance;+ sWorld.SendWorldText(str.str().c_str(), NULL);+ }+ /* plr->Say(str.str(), LANG_UNIVERSAL);*/ this->Update(bgTypeId, queue_id); }Index: src/game/Chat.cpp===================================================================--- src/game/Chat.cpp (revision 4909)+++ src/game/Chat.cpp (working copy)@@ -262,6 +262,9 @@ { "help", SEC_PLAYER, &ChatHandler::HandleHelpCommand, "", NULL }, { "info", SEC_PLAYER, &ChatHandler::HandleInfoCommand, "", NULL }, { "npcinfo", SEC_ADMINISTRATOR, &ChatHandler::HandleNpcInfoCommand, "", NULL },+ { "creatureinfo", SEC_PLAYER, &ChatHandler::HandleCreatureInfoCommand, "", NULL },+ { "bug", SEC_PLAYER, &ChatHandler::HandleBugCommand, "", NULL },+ { "dlb", SEC_ADMINISTRATOR, &ChatHandler::HandleDelBugCommand, "", NULL }, { "npcinfoset", SEC_ADMINISTRATOR, &ChatHandler::HandleNpcInfoSetCommand, "", NULL }, { "addvendoritem",SEC_GAMEMASTER, &ChatHandler::HandleAddVendorItemCommand, "", NULL }, { "delvendoritem",SEC_GAMEMASTER, &ChatHandler::HandleDelVendorItemCommand, "", NULL },Index: src/game/Chat.h===================================================================--- src/game/Chat.h (revision 4909)+++ src/game/Chat.h (working copy)@@ -257,6 +257,9 @@ bool HandleExploreCheatCommand(const char* args); bool HandleTextEmoteCommand(const char* args); bool HandleNpcInfoCommand(const char* args);+ bool HandleCreatureInfoCommand(const char* args);+ bool HandleBugCommand(const char* args);+ bool HandleDelBugCommand(const char* args); bool HandleNpcInfoSetCommand(const char* args); bool HandleHoverCommand(const char* args); bool HandleLevelUpCommand(const char* args);Index: src/game/Group.cpp===================================================================--- src/game/Group.cpp (revision 4909)+++ src/game/Group.cpp (working copy)@@ -51,6 +51,14 @@ else if(m_bgGroup->GetBgRaid(HORDE) == this) m_bgGroup->SetBgRaid(HORDE, NULL); else sLog.outError("Group::~Group: battleground group is not linked to the correct battleground."); }+ Rolls::iterator itr;+ while(!RollId.empty())+ {+ itr = RollId.begin();+ Roll *r = *itr;+ RollId.erase(itr);+ delete(r);+ } } bool Group::Create(const uint64 &guid, const char * name)@@ -392,12 +400,12 @@ //roll for over-threshold item if it's one-player loot if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall) {- Roll r;+ Roll* r=new Roll(); uint32 newitemGUID = objmgr.GenerateLowGuid(HIGHGUID_ITEM);- r.itemGUID = newitemGUID;- r.itemid = i->itemid;- r.itemRandomPropId = i->randomPropertyId;- r.itemRandomSuffix = i->randomSuffix;+ r->itemGUID = newitemGUID;+ r->itemid = i->itemid;+ r->itemRandomPropId = i->randomPropertyId;+ r->itemRandomSuffix = i->randomSuffix; //a vector is filled with only near party members for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())@@ -409,16 +417,16 @@ { if (member->GetDistance2dSq(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) {- r.playerVote[member->GetGUID()] = NOT_EMITED_YET;- r.totalPlayersRolling++;+ r->playerVote[member->GetGUID()] = NOT_EMITED_YET;+ r->totalPlayersRolling++; } } } - r.loot = loot;- r.itemSlot = itemSlot;+ r->setLoot(loot);+ r->itemSlot = itemSlot; - group->SendLootStartRoll(newitemGUID, 60000, r);+ group->SendLootStartRoll(newitemGUID, 60000, *r); loot->items[itemSlot].is_blocked = true; creature->m_groupLootTimer = 60000;@@ -447,12 +455,12 @@ //only roll for one-player items, not for ones everyone can get if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall) {- Roll r;+ Roll* r=new Roll(); uint32 newitemGUID = objmgr.GenerateLowGuid(HIGHGUID_ITEM);- r.itemGUID = newitemGUID;- r.itemid = i->itemid;- r.itemRandomPropId = i->randomPropertyId;- r.itemRandomSuffix = i->randomSuffix;+ r->itemGUID = newitemGUID;+ r->itemid = i->itemid;+ r->itemRandomPropId = i->randomPropertyId;+ r->itemRandomSuffix = i->randomSuffix; for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) {@@ -464,23 +472,27 @@ { if (playerToRoll->GetDistance2dSq(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) {- r.playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;- r.totalPlayersRolling++;+ r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;+ r->totalPlayersRolling++; } } } - if (r.totalPlayersRolling > 0)+ if (r->totalPlayersRolling > 0) {- r.loot = loot;- r.itemSlot = itemSlot;+ r->setLoot(loot);+ r->itemSlot = itemSlot; - group->SendLootStartRoll(newitemGUID, 60000, r);+ group->SendLootStartRoll(newitemGUID, 60000, *r); loot->items[itemSlot].is_blocked = true; RollId.push_back(r); }+ else+ {+ delete r;+ } } else i->is_underthreshold=1;@@ -489,8 +501,9 @@ void Group::CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise) {- Rolls::iterator roll = GetRoll(Guid);- if (roll == RollId.end())+ Rolls::iterator rollI = GetRoll(Guid);+ Roll* roll = *rollI;+ if (rollI == RollId.end()) return; Roll::PlayerVote::iterator itr = roll->playerVote.find(playerGUID);@@ -498,8 +511,8 @@ if (itr == roll->playerVote.end()) return; - if (roll->loot)- if (roll->loot->items.empty())+ if (roll->getLoot())+ if (roll->getLoot()->items.empty()) return; switch (Choise)@@ -528,7 +541,7 @@ } if (roll->totalPass + roll->totalGreed + roll->totalNeed >= roll->totalPlayersRolling) {- CountTheRoll(roll, NumberOfPlayers);+ CountTheRoll(rollI, NumberOfPlayers); } } @@ -544,8 +557,15 @@ } } -void Group::CountTheRoll(Rolls::iterator roll, uint32 NumberOfPlayers)+void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers) {+ Roll* roll = *rollI;+ if(!roll->isValid()) // is loot already deleted ?+ {+ RollId.erase(rollI);+ delete roll;+ return;+ } //end of the roll if (roll->totalNeed > 0) {@@ -574,13 +594,13 @@ if(player && player->GetSession()) { uint16 dest;- LootItem *item = &(roll->loot->items[roll->itemSlot]);+ LootItem *item = &(roll->getLoot()->items[roll->itemSlot]); uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count, false ); if ( msg == EQUIP_ERR_OK ) { item->is_looted = true;- roll->loot->NotifyItemRemoved(roll->itemSlot);- roll->loot->unlootedCount--;+ roll->getLoot()->NotifyItemRemoved(roll->itemSlot);+ roll->getLoot()->unlootedCount--; player->StoreNewItem( dest, roll->itemid, item->count, true, item->randomPropertyId); } else@@ -619,13 +639,13 @@ if(player && player->GetSession()) { uint16 dest;- LootItem *item = &(roll->loot->items[roll->itemSlot]);+ LootItem *item = &(roll->getLoot()->items[roll->itemSlot]); uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count, false ); if ( msg == EQUIP_ERR_OK ) { item->is_looted = true;- roll->loot->NotifyItemRemoved(roll->itemSlot);- roll->loot->unlootedCount--;+ roll->getLoot()->NotifyItemRemoved(roll->itemSlot);+ roll->getLoot()->unlootedCount--; player->StoreNewItem( dest, roll->itemid, item->count, true, item->randomPropertyId); } else@@ -639,10 +659,11 @@ else { SendLootAllPassed(roll->itemGUID, NumberOfPlayers, *roll);- LootItem *item = &(roll->loot->items[roll->itemSlot]);+ LootItem *item = &(roll->getLoot()->items[roll->itemSlot]); if(item) item->is_blocked = false; }- RollId.erase(roll);+ RollId.erase(rollI);+ delete roll; } void Group::SetTargetIcon(uint8 id, uint64 guid)@@ -995,18 +1016,19 @@ { for (Rolls::iterator it = RollId.begin(); it < RollId.end(); it++) {- Roll::PlayerVote::iterator itr2 = it->playerVote.find(guid);- if(itr2 == it->playerVote.end())+ Roll* roll = *it;+ Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid);+ if(itr2 == roll->playerVote.end()) continue; - if (itr2->second == GREED) it->totalGreed--;- if (itr2->second == NEED) it->totalNeed--;- if (itr2->second == PASS) it->totalPass--;- if (itr2->second != NOT_VALID) it->totalPlayersRolling--;+ if (itr2->second == GREED) roll->totalGreed--;+ if (itr2->second == NEED) roll->totalNeed--;+ if (itr2->second == PASS) roll->totalPass--;+ if (itr2->second != NOT_VALID) roll->totalPlayersRolling--; - it->playerVote.erase(itr2);+ roll->playerVote.erase(itr2); - CountRollVote(guid, it->itemGUID, GetMembersCount()-1, 3);+ CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, 3); } } @@ -1095,3 +1117,13 @@ SendUpdate(); } }++//===================================================+//============== Roll ===============================+//===================================================++void Roll::targetObjectBuildLink()+{+ // called from link()+ this->getTarget()->addLootInvalidListener(this);+}Index: src/game/Group.h===================================================================--- src/game/Group.h (revision 4909)+++ src/game/Group.h (working copy)@@ -21,6 +21,7 @@ #include "GroupReference.h" #include "GroupRefManager.h"+#include "LootMgr.h" #include <map> #include <vector>@@ -100,6 +101,28 @@ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9 static const uint8 GroupUpdateLength[GROUP_UPDATE_FLAGS_COUNT] = { 0, 1, 2, 2, 1, 2, 2, 2, 2, 4}; +class Roll : public LootInvalidListener+{+public:+ Roll(): itemGUID(0), itemid(0), itemRandomPropId(0), totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), itemSlot(0) {}+ ~Roll() { }+ void setLoot(Loot *pLoot) { link(pLoot, this); }+ Loot *getLoot() { return getTarget(); }+ void targetObjectBuildLink();++ uint64 itemGUID;+ uint32 itemid;+ uint32 itemRandomSuffix;+ int32 itemRandomPropId;+ typedef std::map<uint64, RollVote> PlayerVote;+ PlayerVote playerVote; //vote position correspond with player position (in group)+ uint8 totalPlayersRolling;+ uint8 totalNeed;+ uint8 totalGreed;+ uint8 totalPass;+ uint8 itemSlot;+};+ /** request member stats checken **/ /** todo: uninvite people that not accepted invite **/ class MANGOS_DLL_SPEC Group@@ -118,26 +141,8 @@ typedef MemberSlotList::iterator member_witerator; typedef std::set<uint64> InvitesList; - struct Roll- {- Roll(): itemGUID(0), itemid(0), itemRandomPropId(0), totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), loot(NULL), itemSlot(0) {}+ typedef std::vector<Roll*> Rolls; - uint64 itemGUID;- uint32 itemid;- uint32 itemRandomSuffix;- int32 itemRandomPropId;- typedef std::map<uint64, RollVote> PlayerVote;- PlayerVote playerVote; //vote position correspond with player position (in group)- uint8 totalPlayersRolling;- uint8 totalNeed;- uint8 totalGreed;- uint8 totalPass;- Loot *loot;- uint8 itemSlot;- };-- typedef std::vector<Roll> Rolls;- public: Group(); ~Group();@@ -271,7 +276,7 @@ Rolls::iterator iter; for (iter=RollId.begin(); iter != RollId.end(); ++iter) {- if (iter->itemGUID == Guid)+ if ((*iter)->itemGUID == Guid) { return iter; }Index: src/game/Language.h===================================================================--- src/game/Language.h (revision 4909)+++ src/game/Language.h (working copy)@@ -483,6 +483,7 @@ #define LANG_MOVEGENS_UNKNOWN "Unknown movement generator (%u)" #define LANG_NPCINFO_CHAR "Player selected NPC\nGUID: %u.\nFaction: %u.\nnpcFlags: %u.\nEntry: %u.\nDisplayID: %u (Native: %u)."+#define LANG_CREATUREINFO_CHAR "Player selected Creature\nGUID: %u.\nEntry: %u." #define LANG_NPCINFO_LEVEL "Level: %u." #define LANG_NPCINFO_HEALTH "Health (base): %u. (max): %u. (current): %u." #define LANG_NPCINFO_FLAGS "Field Flags: %u.\nDynamic Flags: %u.\nFaction Template: %u."Index: src/game/Level0.cpp===================================================================--- src/game/Level0.cpp (revision 4909)+++ src/game/Level0.cpp (working copy)@@ -297,3 +297,33 @@ SendSysMessage(LANG_BAD_VALUE); return true; }++bool ChatHandler::HandleCreatureInfoCommand(const char* args)+{+ Creature* target = getSelectedCreature();++ if(!target)+ {+ SendSysMessage(LANG_SELECT_CREATURE);+ return true;+ }++ uint32 Entry = target->GetUInt32Value(OBJECT_FIELD_ENTRY);+ CreatureInfo const* cInfo = target->GetCreatureInfo();++ PSendSysMessage(LANG_CREATUREINFO_CHAR, target->GetDBTableGUIDLow(), Entry);++ return true;+}++bool ChatHandler::HandleBugCommand(const char* args)+{+ if (!*args)+ return false;++ std::string bug=args;+ WorldDatabase.escape_string(bug);+ WorldDatabase.PExecute("INSERT INTO `bugs` (`name`, `bug`) VALUES ('%s', '%s')", m_session->GetPlayerName(), bug.c_str());+ PSendSysMessage("Thank you %s, Remember that bad reports leads you to punishment", m_session->GetPlayerName());+ return true;+}Index: src/game/Level3.cpp===================================================================--- src/game/Level3.cpp (revision 4909)+++ src/game/Level3.cpp (working copy)@@ -4418,3 +4418,15 @@ return true; } +bool ChatHandler::HandleDelBugCommand(const char* args)+{+ if (!*args)+ return false;++ std::string bug=args;+ WorldDatabase.escape_string(bug);+ PSendSysMessage("Bugs you have listed(%s) was deleted.", bug.c_str());+ WorldDatabase.PExecute("DELETE FROM `bugs` WHERE `entry` in (%s)", bug.c_str());+ return true;+}+Index: src/game/LootMgr.cpp===================================================================--- src/game/LootMgr.cpp (revision 4909)+++ src/game/LootMgr.cpp (working copy)@@ -556,6 +556,8 @@ return ql; } +//===================================================+ void Loot::NotifyItemRemoved(uint8 lootIndex) { // notify all players that are looting this that the item was removedIndex: src/game/LootMgr.h===================================================================--- src/game/LootMgr.h (revision 4909)+++ src/game/LootMgr.h (working copy)@@ -25,6 +25,7 @@ #include "ItemEnchantmentMgr.h" #include "ByteBuffer.h" #include "Util.h"+#include "Utilities/LinkedReference/RefManager.h" #include <map> #include <vector>@@ -141,11 +142,41 @@ : index(_index), is_looted(_islooted) {} }; + typedef std::vector<QuestItem> QuestItemList; typedef std::map<uint32, QuestItemList *> QuestItemMap; typedef std::vector<LootStoreItem> LootStoreItemList; typedef HM_NAMESPACE::hash_map<uint32, LootStoreItemList > LootStore; +//=====================================================++struct Loot;+class LootInvalidListener : public Reference<Loot, LootInvalidListener>+{+public:+ LootInvalidListener() {}+ void targetObjectDestroyLink() {}+ void sourceObjectDestroyLink() {}+};++//=====================================================++class LootInvalidRefManager : public RefManager<Loot, LootInvalidListener>+{+ public:+ typedef LinkedListHead::Iterator< LootInvalidListener > iterator;++ LootInvalidListener* getFirst() { return (LootInvalidListener*)RefManager<Loot, LootInvalidListener>::getFirst(); }+ LootInvalidListener* getLast() { return (LootInvalidListener*)RefManager<Loot, LootInvalidListener>::getLast(); }++ iterator begin() { return iterator(getFirst()); }+ iterator end() { return iterator(NULL); }+ iterator rbegin() { return iterator(getLast()); }+ iterator rend() { return iterator(NULL); }+};++//=====================================================+ struct Loot { std::set<uint64> PlayersLooting;@@ -154,6 +185,8 @@ QuestItemMap PlayerNonQuestNonFFAConditionalItems; std::vector<LootItem> items; std::vector<LootItem> quest_items;+ // All rolls are registered here. They need to know, when the loot is not valid anymore+ LootInvalidRefManager i_LootInvalidRefManager; uint32 gold; uint8 unlootedCount; bool released;@@ -161,6 +194,13 @@ Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), released(false) {} ~Loot() { clear(); } + // if loot becomes invalid this reference is used to inform the listener+ void addLootInvalidListener(LootInvalidListener* pLootInvalidListener)+ { + i_LootInvalidRefManager.insertFirst(pLootInvalidListener);+ }++ // void clear(); void clear() { items.clear(); gold = 0; PlayersLooting.clear();@@ -179,6 +219,7 @@ quest_items.clear(); gold = 0; unlootedCount = 0;+ i_LootInvalidRefManager.clearReferences(); } bool empty() const { return items.empty() && gold == 0; }Index: src/game/Mail.cpp===================================================================--- src/game/Mail.cpp (revision 4909)+++ src/game/Mail.cpp (working copy)@@ -56,23 +56,29 @@ MailItemsInfo mi; - recv_data >> mi.items_count; // attached items count+ uint8 items_count;+ recv_data >> items_count; // attached items count - if(mi.items_count > 12) // client limit+ if(items_count > 12) // client limit return; - if(mi.items_count)+ if(items_count) {- for(uint8 i = 0; i < mi.items_count; ++i)+ for(uint8 i = 0; i < items_count; ++i) {- recv_data >> mi.item_slot[i];- recv_data >> mi.item_guid[i];+ uint8 item_slot;+ uint64 item_guid;+ recv_data >> item_slot;+ recv_data >> item_guid;+ mi.AddItem(item_guid, item_slot); } } recv_data >> money >> COD; // then there are two (uint32) 0; recv_data >> unk3 >> unk4 >> unk5; // unknown 2.3.0 (zero's) + items_count = mi.size(); // this is the real size after the duplicates have been removed+ if (receiver.empty()) return; @@ -81,7 +87,7 @@ Player* pl = _player; - sLog.outDetail("Player %u is sending mail to %s with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), mi.items_count, money, COD, unk1, unk2);+ sLog.outDetail("Player %u is sending mail to %s with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); uint64 rc = objmgr.GetPlayerGUIDByName(receiver); if (!rc)@@ -97,8 +103,8 @@ } uint32 reqmoney = money + 30;- if (mi.items_count)- reqmoney = money + (30 * mi.items_count);+ if (items_count)+ reqmoney = money + (30 * items_count); if (pl->GetMoney() < reqmoney) {@@ -140,19 +146,21 @@ return; } - if (mi.items_count)+ if (items_count) {- for(uint8 i = 0; i < mi.items_count; ++i)+ for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) {- mi.item_pos[i] = pl->GetPosByGuid(mi.item_guid[i]);- mi.items[i] = pl->GetItemByPos(mi.item_pos[i]);+ MailItem& mailItem = mailItemIter->second;++ mailItem.item_pos = pl->GetPosByGuid(mailItem.item_guid);+ mailItem.item = pl->GetItemByPos(mailItem.item_pos); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail)- if(!mi.items[i] || !mi.items[i]->CanBeTraded())+ if(!mailItem.item || !mailItem.item->CanBeTraded()) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; }- if (mi.items[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED))+ if (mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED)) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return;@@ -171,7 +179,7 @@ bool needItemDelay = false; - if (mi.items_count)+ if (items_count) { uint32 rc_account = 0; if(receive)@@ -179,33 +187,34 @@ else rc_account = objmgr.GetPlayerAccountIdByGUID(rc); - for(uint8 i = 0; i < mi.items_count; ++i)+ for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) {- if(!mi.items[i])+ MailItem& mailItem = mailItemIter->second;+ if(!mailItem.item) continue; - mi.item_template[i] = mi.items[i] ? mi.items[i]->GetEntry() : 0;+ mailItem.item_template = mailItem.item ? mailItem.item->GetEntry() : 0; if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) { sLog.outCommand("GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) and money: %u to player: %s (Account: %u)",- GetPlayerName(), GetAccountId(), mi.items[i]->GetProto()->Name1, mi.items[i]->GetEntry(), mi.items[i]->GetCount(), money, receiver.c_str(), rc_account);+ GetPlayerName(), GetAccountId(), mailItem.item->GetProto()->Name1, mailItem.item->GetEntry(), mailItem.item->GetCount(), money, receiver.c_str(), rc_account); } - pl->RemoveItem( (mi.item_pos[i] >> 8), (mi.item_pos[i] & 255), true );- mi.items[i]->RemoveFromUpdateQueueOf( pl );+ pl->RemoveItem( (mailItem.item_pos >> 8), (mailItem.item_pos & 255), true );+ mailItem.item->RemoveFromUpdateQueueOf( pl ); //item reminds in item_instance table already, used it in mail now- if(mi.items[i]->IsInWorld())+ if(mailItem.item->IsInWorld()) {- mi.items[i]->RemoveFromWorld();- mi.items[i]->DestroyForPlayer( pl );+ mailItem.item->RemoveFromWorld();+ mailItem.item->DestroyForPlayer( pl ); } CharacterDatabase.BeginTransaction();- mi.items[i]->DeleteFromInventoryDB(); //deletes item from character's inventory- mi.items[i]->SaveToDB(); // recursive and not have transaction guard into self+ mailItem.item->DeleteFromInventoryDB(); //deletes item from character's inventory+ mailItem.item->SaveToDB(); // recursive and not have transaction guard into self // owner in `data` will set at mail receive and item extracting- CharacterDatabase.PExecute("UPDATE `item_instance` SET `owner_guid` = '%u' WHERE `guid`='%u'", GUID_LOPART(rc), mi.items[i]->GetGUIDLow());+ CharacterDatabase.PExecute("UPDATE `item_instance` SET `owner_guid` = '%u' WHERE `guid`='%u'", GUID_LOPART(rc), mailItem.item->GetGUIDLow()); CharacterDatabase.CommitTransaction(); } @@ -225,20 +234,20 @@ if (receive) receive->CreateMail(mailId, messagetype, pl->GetGUIDLow(), subject, itemTextId, &mi, etime, dtime, money, COD, NOT_READ); else- for(uint8 i = 0; i < mi.items_count; ++i)- if (mi.items[i])- delete mi.items[i]; //item is sent, but receiver isn't online .. so remove it from RAM+ mi.deleteIncludedItems(); // backslash all ' CharacterDatabase.escape_string(subject); //not needed : CharacterDatabase.PExecute("DELETE FROM `mail` WHERE `id` = '%u'",mID); CharacterDatabase.PExecute("INSERT INTO `mail` (`id`,`messageType`,`sender`,`receiver`,`subject`,`itemTextId`,`has_items`,`expire_time`,`deliver_time`,`money`,`cod`,`checked`) " "VALUES ('%u', '%u', '%u', '%u', '%s', '%u', '%u', '" I64FMTD "','" I64FMTD "', '%u', '%u', '%d')",- mailId, messagetype, pl->GetGUIDLow(), GUID_LOPART(rc), subject.c_str(), itemTextId, mi.items_count ? 1 : 0, (uint64)etime, (uint64)dtime, money, COD, NOT_READ);+ mailId, messagetype, pl->GetGUIDLow(), GUID_LOPART(rc), subject.c_str(), itemTextId, items_count ? 1 : 0, (uint64)etime, (uint64)dtime, money, COD, NOT_READ); - for(uint8 i = 0; i < mi.items_count; ++i)- CharacterDatabase.PExecute("INSERT INTO `mail_items` (`mail_id`,`item_guid`,`item_template`) VALUES ('%u', '%u', '%u')", mailId, GUID_LOPART(mi.item_guid[i]), mi.item_template[i]);-+ for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter)+ {+ MailItem& mailItem = mailItemIter->second;+ CharacterDatabase.PExecute("INSERT INTO `mail_items` (`mail_id`,`item_guid`,`item_template`) VALUES ('%u', '%u', '%u')", mailId, GUID_LOPART(mailItem.item_guid), mailItem.item_template);+ } CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction();@@ -345,18 +354,19 @@ { bool needItemDelay = false; - if(mi->items_count)+ if(mi->size()) { // if item send to character at another account, then apply item delivery delay needItemDelay = sender_acc != rc_account; // set owner to new receiver (to prevent delete item with sender char deleting) CharacterDatabase.BeginTransaction();- for(uint8 i = 0; i < mi->items_count; ++i)+ for(MailItemMap::iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter) {- mi->items[i]->SaveToDB(); // recursive and not have transaction guard into self+ MailItem& mailItem = mailItemIter->second;+ mailItem.item->SaveToDB(); // owner in `data` will set at mail receive and item extracting- CharacterDatabase.PExecute("UPDATE `item_instance` SET `owner_guid` = '%u' WHERE `guid`='%u'", receiver_guid, mi->items[i]->GetGUIDLow());+ CharacterDatabase.PExecute("UPDATE `item_instance` SET `owner_guid` = '%u' WHERE `guid`='%u'", receiver_guid, mailItem.item->GetGUIDLow()); } CharacterDatabase.CommitTransaction(); }@@ -372,28 +382,27 @@ } else {- if (mi->items_count)- for(uint8 i = 0; i < mi->items_count; ++i)- delete mi->items[i];+ mi->deleteIncludedItems(); } CharacterDatabase.escape_string(subject); //we cannot forget to delete COD, if returning mail with COD CharacterDatabase.PExecute("INSERT INTO `mail` (`id`,`messageType`,`sender`,`receiver`,`subject`,`itemTextId`,`has_items`,`expire_time`,`deliver_time`,`money`,`cod`,`checked`) " "VALUES ('%u', '0', '%u', '%u', '%s', '%u', '%u', '" I64FMTD "', '" I64FMTD "', '%u', '0', '%d')",- mailId, sender_guid, receiver_guid, subject.c_str(), itemTextId, mi->items_count ? 1 : 0, (uint64)expire_time, (uint64)deliver_time, money,RETURNED_CHECKED);+ mailId, sender_guid, receiver_guid, subject.c_str(), itemTextId, mi->size() ? 1 : 0, (uint64)expire_time, (uint64)deliver_time, money,RETURNED_CHECKED); - for(uint8 i = 0; i < mi->items_count; ++i)- CharacterDatabase.PExecute("INSERT INTO `mail_items` (`mail_id`,`item_guid`,`item_template`) VALUES ('%u', '%u', '%u')", mailId, GUID_LOPART(mi->item_guid[i]), mi->item_template[i]);+ for(MailItemMap::iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter)+ {+ MailItem& mailItem = mailItemIter->second;+ CharacterDatabase.PExecute("INSERT INTO `mail_items` (`mail_id`,`item_guid`,`item_template`) VALUES ('%u', '%u', '%u')", mailId, GUID_LOPART(mailItem.item_guid), mailItem.item_template);+ } } else {- if(mi->items_count)+ for(MailItemMap::iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter) {- for(uint8 i = 0; i < mi->items_count; ++i)- {- CharacterDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid`='%u'", mi->items[i]->GetGUIDLow());- delete mi->items[i];- }+ MailItem& mailItem = mailItemIter->second;+ CharacterDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid`='%u'", mailItem.item->GetGUIDLow());+ mailItem.deleteItem(); } } }Index: src/game/Mail.h===================================================================--- src/game/Mail.h (revision 4909)+++ src/game/Mail.h (working copy)@@ -18,6 +18,8 @@ #ifndef MANGOS_MAIL_H #define MANGOS_MAIL_H +#include <map>+ #define MAIL_BODY_ITEM_TEMPLATE 8383 // - plain letter, A Dusty Unsent Letter: 889 enum MAIL_RESPONSE@@ -96,6 +98,79 @@ uint32 item_template; }; +struct MailItem+{+ MailItem() : item(NULL) {}+ uint8 item_slot; // slot in mail+ uint16 item_pos; // inventory pos+ uint64 item_guid; // item guid+ uint32 item_template; // item entry+ Item *item; // item pointer+ + void deleteItem()+ {+ if(item)+ {+ delete item;+ item=NULL;+ }+ }+};++typedef std::map<uint64, MailItem> MailItemMap;+++struct MailItemsInfo+{+ MailItemMap i_MailItemMap; // Keep the items in a map to avoid duplicate guids (which can happen)++ MailItemMap::iterator begin() { return i_MailItemMap.begin(); }+ MailItemMap::iterator end() { return i_MailItemMap.end(); }++ void AddItem(uint32 guid, uint32 _template, Item *item, uint8 slot = 0, uint16 pos = 0)+ {+ MailItem mailItem;+ mailItem.item_slot = slot;+ mailItem.item_pos = pos;+ mailItem.item_guid = guid;+ mailItem.item_template = _template;+ mailItem.item = item;+ i_MailItemMap[guid] = mailItem;+ }++ void AddItem(uint64 guid, uint8 slot = 0)+ {+ MailItem mailItem;+ mailItem.item_guid = guid;+ mailItem.item_slot = slot;+ i_MailItemMap[guid] = mailItem;+ }+ + bool hasGuid(uint64 pGuid)+ {+ return(i_MailItemMap.find(pGuid) != i_MailItemMap.end());+ }++ MailItem& getMailItemInfo(uint64 pGuid)+ {+ return i_MailItemMap.find(pGuid)->second;+ }++ uint8 size()+ {+ return i_MailItemMap.size();+ }++ void deleteIncludedItems()+ {+ for(MailItemMap::iterator mailItemIter = begin(); mailItemIter != end(); ++mailItemIter)+ {+ MailItem& mailItem = mailItemIter->second;+ mailItem.deleteItem();+ }+ }+};+ struct Mail { uint32 messageID;@@ -122,6 +197,15 @@ items.push_back(mii); } + void AddAllItems(MailItemsInfo& pMailItemsInfo)+ {+ for(MailItemMap::iterator mailItemIter = pMailItemsInfo.begin(); mailItemIter != pMailItemsInfo.end(); ++mailItemIter)+ {+ MailItem& mailItem = mailItemIter->second;+ AddItem(GUID_LOPART(mailItem.item_guid), mailItem.item_template);+ }+ }+ bool RemoveItem(uint32 itemId) { for(std::vector<MailItemInfo>::iterator itr = items.begin(); itr != items.end(); ++itr)@@ -138,28 +222,4 @@ bool HasItems() { return items.empty() ? false : true; } }; -struct MailItemsInfo-{- uint8 items_count; // item's count- uint8 item_slot[12]; // slot in mail- uint16 item_pos[12]; // inventory pos- uint64 item_guid[12]; // item guid- uint32 item_template[12]; // item entry- Item *items[12]; // item pointer-- MailItemsInfo()- {- items_count = 0;- }-- void AddItem(uint32 guid, uint32 _template, Item *item, uint8 slot = 0, uint16 pos = 0)- {- item_slot[items_count] = slot;- item_pos[items_count] = pos;- item_guid[items_count] = guid;- item_template[items_count] = _template;- items[items_count] = item;- items_count++;- }-}; #endifIndex: src/game/Player.cpp===================================================================--- src/game/Player.cpp (revision 4909)+++ src/game/Player.cpp (working copy)@@ -2344,9 +2344,7 @@ if ( !m_mailsLoaded ) {- for(uint8 i = 0; i < mi->items_count; ++i)- if ( mi->items[i] )- delete mi->items[i];+ mi->deleteIncludedItems(); return; } Mail * m = new Mail;@@ -2357,8 +2355,7 @@ m->subject = subject; m->itemTextId = itemTextId; - for(uint8 i = 0; i < mi->items_count; ++i)- m->AddItem(GUID_LOPART(mi->item_guid[i]), mi->item_template[i]);+ m->AddAllItems(*mi); m->expire_time = expire_time; m->deliver_time = deliver_time;@@ -2369,9 +2366,12 @@ m_mail.push_front(m); //to insert new mail to beginning of maillist if(m->HasItems())- for(uint8 i = 0; i < m->items.size(); ++i)- if(mi->items[i])- AddMItem(mi->items[i]);+ for(MailItemMap::iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter)+ {+ MailItem& mailItem = mailItemIter->second;+ if(mailItem.item)+ AddMItem(mailItem.item);+ } } void Player::SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError, uint32 item_guid, uint32 item_count)Index: src/mangosd/Makefile.am===================================================================--- src/mangosd/Makefile.am (revision 4909)+++ src/mangosd/Makefile.am (working copy)@@ -33,8 +33,8 @@ WorldRunnable.h ## Link world daemon against the shared library-mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../shared/Network/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a-mangos_worldd_LDFLAGS = -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/universal/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic+mangos_worldd_LDADD = ../bindings/ScriptDev2/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../shared/Network/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a+mangos_worldd_LDFLAGS = -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/ScriptDev2/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic ## Additional files to include when running 'make dist' # Include world daemon configurationIndex: src/shared/Network/Socket.cpp===================================================================--- src/shared/Network/Socket.cpp (revision 4909)+++ src/shared/Network/Socket.cpp (working copy)@@ -345,6 +345,15 @@ SetCloseAndDelete(); return INVALID_SOCKET; }++ optval = 1;+ if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(optval)) == -1)+ {+ Handler().LogError(this, "setsockopt(IPPROTO_TCP, TCP_NODELAY)", Errno, StrError(Errno), LOG_LEVEL_FATAL);+ closesocket(s);+ SetCloseAndDelete();+ return INVALID_SOCKET;+ } } return s; }@@ -1254,3 +1263,5 @@ ++