Index: 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 and Index: 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 = ScriptDev2 Index: 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 #include @@ -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 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 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 Rolls; - uint64 itemGUID; - uint32 itemid; - uint32 itemRandomSuffix; - int32 itemRandomPropId; - typedef std::map 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 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 removed Index: 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 #include @@ -141,11 +142,41 @@ : index(_index), is_looted(_islooted) {} }; + typedef std::vector QuestItemList; typedef std::map QuestItemMap; typedef std::vector LootStoreItemList; typedef HM_NAMESPACE::hash_map LootStore; +//===================================================== + +struct Loot; +class LootInvalidListener : public Reference +{ +public: + LootInvalidListener() {} + void targetObjectDestroyLink() {} + void sourceObjectDestroyLink() {} +}; + +//===================================================== + +class LootInvalidRefManager : public RefManager +{ + public: + typedef LinkedListHead::Iterator< LootInvalidListener > iterator; + + LootInvalidListener* getFirst() { return (LootInvalidListener*)RefManager::getFirst(); } + LootInvalidListener* getLast() { return (LootInvalidListener*)RefManager::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 PlayersLooting; @@ -154,6 +185,8 @@ QuestItemMap PlayerNonQuestNonFFAConditionalItems; std::vector items; std::vector 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 + #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 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::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++; - } -}; #endif Index: 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 configuration Index: 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 @@ + +