Index: src/shared/Database/Database.h =================================================================== --- src/shared/Database/Database.h (révision 5105) +++ src/shared/Database/Database.h (copie de travail) @@ -59,10 +59,14 @@ bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql); template bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql); + template + bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql); template bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...) ATTR_PRINTF(4,5); template bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(5,6); + template + bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) ATTR_PRINTF(5,6); template bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder); template Index: src/shared/Database/DatabaseImpl.h =================================================================== --- src/shared/Database/DatabaseImpl.h (révision 5105) +++ src/shared/Database/DatabaseImpl.h (copie de travail) @@ -45,6 +45,18 @@ return true; } +template +bool +Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql) +{ + if (!sql) return false; + ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current(); + QueryQueues::iterator itr = m_queryQueues.find(queryThread); + if (itr == m_queryQueues.end()) return false; + m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback(object, method, (QueryResult*)NULL, param1, param2, param3), itr->second)); + return true; +} + template bool Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...) @@ -87,6 +99,28 @@ return AsyncQuery(object, method, param1, szQuery); } + +template +bool +Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) +{ + if(!format) return false; + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap ); + va_end(ap); + + if(res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return false; + } + + return AsyncQuery(object, method, param1, param2, param3, szQuery); +} + template bool Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder) Index: src/game/Player.cpp =================================================================== --- src/game/Player.cpp (révision 5105) +++ src/game/Player.cpp (copie de travail) @@ -14077,27 +14065,43 @@ tokens[index] = buf; } -void Player::SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid) +class PlayerCallback { - Tokens tokens; - if(!LoadValuesArrayFromDB(tokens,guid)) - return; + public: + void CallbackSetUInt32ValueInDB(QueryResult* result, uint16 index, uint32 value, uint64 guid) + { + if(!result) + return; + + Tokens tokens; + + Field *fields = result->Fetch(); - if(index >= tokens.size()) - return; + tokens = StrSplit(fields[0].GetCppString(), " "); - char buf[11]; - snprintf(buf,11,"%u",value); - tokens[index] = buf; + delete result; - SaveValuesArrayInDB(tokens,guid); + if(index >= tokens.size()) + return; + + char buf[11]; + snprintf(buf,11,"%u",value); + tokens[index] = buf; + + Player::SaveValuesArrayInDB(tokens,guid); + } +} pCallback; + +void Player::SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid) +{ + CharacterDatabase.AsyncPQuery(&pCallback, &PlayerCallback::CallbackSetUInt32ValueInDB, index, value, guid, "SELECT `data` FROM `character` WHERE `guid`='%u'", GUID_LOPART(guid)); } void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid) { uint32 temp; memcpy(&temp, &value, sizeof(value)); Player::SetUInt32ValueInDB(index, temp, guid); } void Player::SendAttackSwingNotStanding() Index: src/game/ObjectMgr.h =================================================================== --- src/game/ObjectMgr.h (révision 5105) +++ src/game/ObjectMgr.h (copie de travail) @@ -277,6 +277,7 @@ //auction messages void SendAuctionWonMail( AuctionEntry * auction ); + void CallbackSendAuctionWonMail(QueryResult *result, AuctionEntry *auction ); void SendAuctionSuccessfulMail( AuctionEntry * auction ); void SendAuctionExpiredMail( AuctionEntry * auction ); uint32 GetAuctionCut( uint32 location, uint32 highBid ); Index: src/game/ObjectMgr.cpp =================================================================== --- src/game/ObjectMgr.cpp (révision 5105) +++ src/game/ObjectMgr.cpp (copie de travail) @@ -37,6 +37,7 @@ #include "GameEvent.h" #include "Spell.h" #include "Chat.h" +#include "Database/DatabaseImpl.h" INSTANTIATE_SINGLETON_1(ObjectMgr); @@ -242,49 +243,17 @@ uint64 bidder_guid = MAKE_GUID(auction->bidder,HIGHGUID_PLAYER); Player *bidder = objmgr.GetPlayer(bidder_guid); - uint32 bidder_accId = 0; - - // data for gm.log - if( sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) + // prevent DB access for online player + if(bidder) { - uint32 bidder_security = 0; - std::string bidder_name; - if (bidder) - { - bidder_accId = bidder->GetSession()->GetAccountId(); - bidder_security = bidder->GetSession()->GetSecurity(); - bidder_name = bidder->GetName(); - } - else - { - bidder_accId = GetPlayerAccountIdByGUID(bidder_guid); - bidder_security = GetSecurityByAccount(bidder_accId); - - if(bidder_security > SEC_PLAYER ) // not do redundant DB requests - { - if(!GetPlayerNameByGUID(bidder_guid,bidder_name)) - bidder_name = LANG_UNKNOWN; - } - } - - if( bidder_security > SEC_PLAYER ) - { - std::string owner_name; - if(!GetPlayerNameByGUID(auction->owner,owner_name)) - owner_name = LANG_UNKNOWN; - - uint32 owner_accid = GetPlayerAccountIdByGUID(auction->owner); - - sLog.outCommand("GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", - bidder_name.c_str(),bidder_accId,pItem->GetProto()->Name1,pItem->GetEntry(),pItem->GetCount(),auction->bid,owner_name.c_str(),owner_accid); - } + std::string bidder_name = bidder->GetName(); } - else if(!bidder) - bidder_accId = GetPlayerAccountIdByGUID(bidder_guid); + else + { + CharacterDatabase.AsyncPQuery(this, &ObjectMgr::CallbackSendAuctionWonMail, auction, "SELECT `name` FROM `character` WHERE `guid` = '%u'", GUID_LOPART(bidder_guid)); + return; + } - // receiver exist - if(bidder || bidder_accId) - { std::ostringstream msgAuctionWonSubject; msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON; @@ -305,32 +274,74 @@ CharacterDatabase.PExecute("UPDATE `item_instance` SET `owner_guid` = '%u' WHERE `guid`='%u'",auction->bidder,pItem->GetGUIDLow()); CharacterDatabase.CommitTransaction(); - if (bidder) - { - bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template); + bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template); - MailItemsInfo mi; - mi.AddItem(auction->item_guidlow, auction->item_template, pItem); - bidder->CreateMail(mailId, MAIL_AUCTION, auction->location, msgAuctionWonSubject.str(), itemTextId, &mi, etime, dtime, 0, 0, AUCTION_CHECKED); - } - else - { - objmgr.RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! - delete pItem; - } + MailItemsInfo mi; + mi.AddItem(auction->item_guidlow, auction->item_template, pItem); + bidder->CreateMail(mailId, MAIL_AUCTION, auction->location, msgAuctionWonSubject.str(), itemTextId, &mi, etime, dtime, 0, 0, AUCTION_CHECKED); + CharacterDatabase.PExecute("INSERT INTO `mail` (`id`,`messageType`,`sender`,`receiver`,`subject`,`itemTextId`,`has_items`,`expire_time`,`deliver_time`,`money`,`cod`,`checked`) " "VALUES ('%u', '%d', '%u', '%u', '%s', '%u', '1', '" I64FMTD "','" I64FMTD "', '0', '0', '%d')", mailId, MAIL_AUCTION, auction->location, auction->bidder, msgAuctionWonSubject.str().c_str(), itemTextId, (uint64)etime, (uint64)dtime, AUCTION_CHECKED); CharacterDatabase.PExecute("INSERT INTO `mail_items` (`mail_id`,`item_guid`,`item_template`) VALUES ('%u', '%u', '%u')", mailId, auction->item_guidlow, auction->item_template); - } - // receiver not exist - else + +} + +//does not clear ram +void ObjectMgr::CallbackSendAuctionWonMail(QueryResult *result, AuctionEntry* auction) +{ + if(!result) + return; + + if(!auction) + return; + + Item *pItem = objmgr.GetAItem(auction->item_guidlow); + + if(!pItem) + return; + + uint64 bidder_guid = MAKE_GUID(auction->bidder,HIGHGUID_PLAYER); + + std::string bidder_name = (*result)[0].GetCppString(); + + delete result; + + uint32 bidder_accId = GetPlayerAccountIdByGUID(bidder_guid); + + if(bidder_accId) { + std::ostringstream msgAuctionWonSubject; + msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON; + + std::ostringstream msgAuctionWonBody; + msgAuctionWonBody.width(16); + msgAuctionWonBody << std::right << std::hex << auction->owner; + msgAuctionWonBody << std::dec << ":" << auction->bid << ":" << auction->buyout; + sLog.outDebug( "AuctionWon body string : %s", msgAuctionWonBody.str().c_str() ); + + //prepare mail data... : + uint32 mailId = this->GenerateMailID(); + uint32 itemTextId = this->CreateItemText( msgAuctionWonBody.str() ); + time_t dtime = time(NULL); //Will always be instant when from Auction House. + time_t etime = dtime + (30 * DAY); + + // set owner to bidder (to prevent delete item with sender char deleting) + // owner in `data` will set at mail receive and item extracting + CharacterDatabase.PExecute("UPDATE `item_instance` SET `owner_guid` = '%u' WHERE `guid`='%u'",auction->bidder,pItem->GetGUIDLow()); + CharacterDatabase.CommitTransaction(); + + objmgr.RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! + delete pItem; + } + // receiver not exist + else + { CharacterDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid`='%u'", pItem->GetGUIDLow()); objmgr.RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! delete pItem; - } + } } //call this method to send mail to auction owner, when auction is successful, it does not clear ram Index: src/framework/Utilities/Callback.h =================================================================== --- src/framework/Utilities/Callback.h (révision 5105) +++ src/framework/Utilities/Callback.h (copie de travail) @@ -23,10 +23,31 @@ namespace MaNGOS { - template < class Class, typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void, typename ParamType4 = void > + + template < class Class, typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void, typename ParamType4 = void, typename ParamType5 = void > class _Callback { protected: + typedef void (Class::*Method)(ParamType1, ParamType2, ParamType3, ParamType4, ParamType5); + Class *m_object; + Method m_method; + ParamType1 m_param1; + ParamType2 m_param2; + ParamType3 m_param3; + ParamType4 m_param4; + ParamType5 m_param5; + void _Execute() { (m_object->*m_method)(m_param1, m_param2, m_param3, m_param4, m_param5); } + public: + _Callback(Class *object, Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4, ParamType5 param5) + : m_object(object), m_method(method), m_param1(param1), m_param2(param2), m_param3(param3), m_param4(param4), m_param5(param5) {} + _Callback(_Callback < Class, ParamType1, ParamType2, ParamType3, ParamType4, ParamType5> const& cb) + : m_object(cb.object), m_method(cb.m_method), m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3), m_param4(cb.m_param4), m_param5(cb.m_param5) {} + }; + + template < class Class, typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4 > + class _Callback < Class, ParamType1, ParamType2, ParamType3, ParamType4 > + { + protected: typedef void (Class::*Method)(ParamType1, ParamType2, ParamType3, ParamType4); Class *m_object; Method m_method; @@ -38,10 +59,11 @@ public: _Callback(Class *object, Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4) : m_object(object), m_method(method), m_param1(param1), m_param2(param2), m_param3(param3), m_param4(param4) {} - _Callback(_Callback < Class, ParamType1, ParamType2, ParamType3, ParamType4> const& cb) - : m_object(cb.object), m_method(cb.m_method), m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3), m_param4(cb.m_param4) {} + _Callback(_Callback < Class, ParamType1, ParamType2, ParamType3, ParamType4 > const& cb) + : m_object(cb.m_object), m_method(cb.m_method), m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3), m_param4(cb.m_param4) {} }; + template < class Class, typename ParamType1, typename ParamType2, typename ParamType3 > class _Callback < Class, ParamType1, ParamType2, ParamType3 > { @@ -55,9 +77,9 @@ void _Execute() { (m_object->*m_method)(m_param1, m_param2, m_param3); } public: _Callback(Class *object, Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3) - : m_object(object), m_method(method), m_param1(param1), m_param2(param2) {} + : m_object(object), m_method(method), m_param1(param1), m_param2(param2), m_param3(param3) {} _Callback(_Callback < Class, ParamType1, ParamType2, ParamType3 > const& cb) - : m_object(cb.object), m_method(cb.m_method), m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3) {} + : m_object(cb.m_object), m_method(cb.m_method), m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3) {} }; template < class Class, typename ParamType1, typename ParamType2 > @@ -208,12 +230,26 @@ QueryResult* GetResult() { return CB::m_param1; } }; - template < class Class, typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void > + + template < class Class, typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void, typename ParamType4 = void > class QueryCallback : + public _IQueryCallback< _Callback < Class, QueryResult*, ParamType1, ParamType2, ParamType3, ParamType4 > > + { + private: + typedef _Callback < Class, QueryResult*, ParamType1, ParamType2, ParamType3, ParamType4 > QC4; + public: + QueryCallback(Class *object, typename QC4::Method method, QueryResult* result, ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4) + : _IQueryCallback< QC4 >(QC4(object, method, result, param1, param2, param3, param4)) {} + }; + + + + template < class Class, typename ParamType1, typename ParamType2, typename ParamType3 > + class QueryCallback < Class, ParamType1, ParamType2, ParamType3 > : public _IQueryCallback< _Callback < Class, QueryResult*, ParamType1, ParamType2, ParamType3 > > { private: - typedef _Callback < Class, QueryResult*, ParamType1, ParamType2, ParamType3 > QC3; + typedef _Callback < Class, QueryResult*, ParamType1, ParamType2, ParamType3> QC3; public: QueryCallback(Class *object, typename QC3::Method method, QueryResult* result, ParamType1 param1, ParamType2 param2, ParamType3 param3) : _IQueryCallback< QC3 >(QC3(object, method, result, param1, param2, param3)) {}