[11704] Resolve possible crash in auction code for paiment pending state.

Source of crash in sharing item object for sent mail to new owner
and in same time use it in still existed auction for show pending paiment.
Crash possible if new onwer get mail in less hour delay and will drop item
at receive.

Solution: Added fields in memory auction object and table `auction` for
store item stack size and random property id. This let not use auction item
except points where item send to owner at expire and new owner at
buyout/timeout auction with bid.
This commit is contained in:
VladimirMangos 2011-07-02 03:31:09 +04:00
parent 0daf12a348
commit 0f0fa22607
7 changed files with 129 additions and 103 deletions

View file

@ -21,7 +21,7 @@
DROP TABLE IF EXISTS `character_db_version`; DROP TABLE IF EXISTS `character_db_version`;
CREATE TABLE `character_db_version` ( CREATE TABLE `character_db_version` (
`required_11620_01_characters_character_equipmentsets` bit(1) default NULL `required_11704_01_characters_auction` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
-- --
@ -144,6 +144,8 @@ CREATE TABLE `auction` (
`houseid` int(11) unsigned NOT NULL default '0', `houseid` int(11) unsigned NOT NULL default '0',
`itemguid` int(11) unsigned NOT NULL default '0', `itemguid` int(11) unsigned NOT NULL default '0',
`item_template` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier', `item_template` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier',
`item_count` int(11) unsigned NOT NULL default '0',
`item_randompropertyid` int(11) NOT NULL default '0',
`itemowner` int(11) unsigned NOT NULL default '0', `itemowner` int(11) unsigned NOT NULL default '0',
`buyoutprice` int(11) NOT NULL default '0', `buyoutprice` int(11) NOT NULL default '0',
`time` bigint(40) NOT NULL default '0', `time` bigint(40) NOT NULL default '0',
@ -152,8 +154,7 @@ CREATE TABLE `auction` (
`lastbid` int(11) NOT NULL default '0', `lastbid` int(11) NOT NULL default '0',
`startbid` int(11) NOT NULL default '0', `startbid` int(11) NOT NULL default '0',
`deposit` int(11) NOT NULL default '0', `deposit` int(11) NOT NULL default '0',
PRIMARY KEY (`id`), PRIMARY KEY (`id`)
UNIQUE KEY `item_guid` (`itemguid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --

View file

@ -0,0 +1,10 @@
ALTER TABLE character_db_version CHANGE COLUMN required_11620_01_characters_character_equipmentsets required_11704_01_characters_auction bit;
ALTER TABLE `auction`
DROP KEY `item_guid`,
ADD COLUMN `item_count` int(11) unsigned NOT NULL default '0' AFTER `item_template`,
ADD COLUMN `item_randompropertyid` int(11) NOT NULL default '0' AFTER `item_count`;
UPDATE auction, item_instance
SET auction.item_count = SUBSTRING_INDEX(SUBSTRING_INDEX(item_instance.data, ' ', 14 + 1), ' ', -1)
WHERE auction.itemguid = item_instance.guid;

View file

@ -107,11 +107,7 @@ void WorldSession::SendAuctionBidderNotification(AuctionEntry* auction)
data << uint32(auction->moneyDeliveryTime ? 0 : auction->bid); data << uint32(auction->moneyDeliveryTime ? 0 : auction->bid);
data << uint32(auction->GetAuctionOutBid()); // AuctionOutBid? data << uint32(auction->GetAuctionOutBid()); // AuctionOutBid?
data << uint32(auction->itemTemplate); data << uint32(auction->itemTemplate);
data << int32(auction->itemRandomPropertyId);
Item *item = sAuctionMgr.GetAItem(auction->itemGuidLow);
uint32 randomId = item ? item->GetItemRandomPropertyId() : 0;
data << uint32(randomId); // random property (value > 0) or suffix (value < 0)
SendPacket(&data); SendPacket(&data);
} }
@ -131,11 +127,7 @@ void WorldSession::SendAuctionOwnerNotification(AuctionEntry* auction)
// if guid!=0, client updates auctions with new bid, outbid and bidderGuid, else it shows error messages as described above // if guid!=0, client updates auctions with new bid, outbid and bidderGuid, else it shows error messages as described above
data << guid; // bidder guid data << guid; // bidder guid
data << uint32(auction->itemTemplate); // item entry data << uint32(auction->itemTemplate); // item entry
data << uint32(auction->itemRandomPropertyId);
Item *item = sAuctionMgr.GetAItem(auction->itemGuidLow);
uint32 randomId = item ? item->GetItemRandomPropertyId() : 0;
data << uint32(randomId); // random property (value > 0) or suffix (value < 0)
float timeLeft = float(auction->moneyDeliveryTime - time(NULL)) / float(DAY); float timeLeft = float(auction->moneyDeliveryTime - time(NULL)) / float(DAY);
@ -150,11 +142,7 @@ void WorldSession::SendAuctionRemovedNotification(AuctionEntry* auction)
WorldPacket data(SMSG_AUCTION_REMOVED_NOTIFICATION, (3*4)); WorldPacket data(SMSG_AUCTION_REMOVED_NOTIFICATION, (3*4));
data << uint32(auction->Id); data << uint32(auction->Id);
data << uint32(auction->itemTemplate); data << uint32(auction->itemTemplate);
data << uint32(auction->itemRandomPropertyId);
Item *item = sAuctionMgr.GetAItem(auction->itemGuidLow);
uint32 randomId = item ? item->GetItemRandomPropertyId() : 0;
data << uint32(randomId); // random property (value > 0) or suffix (value < 0)
SendPacket(&data); SendPacket(&data);
} }
@ -471,6 +459,8 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data)
auction->bidder = pl->GetGUIDLow(); auction->bidder = pl->GetGUIDLow();
auction->bid = price; auction->bid = price;
SendAuctionCommandResult(auction, AUCTION_BID_PLACED, AUCTION_OK);
if (auction_owner) if (auction_owner)
auction_owner->GetSession()->SendAuctionOwnerNotification(auction); auction_owner->GetSession()->SendAuctionOwnerNotification(auction);
@ -478,8 +468,6 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data)
// after this update we should save player's money ... // after this update we should save player's money ...
CharacterDatabase.PExecute("UPDATE auction SET buyguid = '%u', lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); CharacterDatabase.PExecute("UPDATE auction SET buyguid = '%u', lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id);
SendAuctionCommandResult(auction, AUCTION_BID_PLACED, AUCTION_OK);
} }
else // buyout else // buyout
{ {
@ -497,15 +485,11 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data)
auction->bidder = pl->GetGUIDLow(); auction->bidder = pl->GetGUIDLow();
auction->bid = auction->buyout; auction->bid = auction->buyout;
GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout);
auction->moneyDeliveryTime = time(NULL) + HOUR;
sAuctionMgr.SendAuctionWonMail(auction);
SendAuctionCommandResult(auction, AUCTION_BID_PLACED, AUCTION_OK); SendAuctionCommandResult(auction, AUCTION_BID_PLACED, AUCTION_OK);
CharacterDatabase.PExecute("UPDATE auction SET moneyTime = '" UI64FMTD "', buyguid = '%u', lastbid = '%u' WHERE id = '%u'", (uint64)auction->moneyDeliveryTime, auction->bidder, auction->bid, auction->Id); auction->AuctionBidWinning();
GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout);
} }
CharacterDatabase.BeginTransaction(); CharacterDatabase.BeginTransaction();
pl->SaveInventoryAndGoldToDB(); pl->SaveInventoryAndGoldToDB();

View file

@ -124,8 +124,8 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction)
uint32 owner_accid = ownerGuid ? sObjectMgr.GetPlayerAccountIdByGUID(ownerGuid) : 0; uint32 owner_accid = ownerGuid ? sObjectMgr.GetPlayerAccountIdByGUID(ownerGuid) : 0;
sLog.outCommand(bidder_accId,"GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", sLog.outCommand(bidder_accId,"GM %s (Account: %u) won item in auction (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); bidder_name.c_str(), bidder_accId, auction->itemTemplate, auction->itemCount, auction->bid, owner_name.c_str(), owner_accid);
} }
} }
else if (!bidder) else if (!bidder)
@ -148,8 +148,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction)
// set owner to bidder (to prevent delete item with sender char deleting) // set owner to bidder (to prevent delete item with sender char deleting)
// owner in `data` will set at mail receive and item extracting // 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.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", auction->bidder, auction->itemGuidLow);
CharacterDatabase.CommitTransaction();
if (bidder) if (bidder)
{ {
@ -157,8 +156,10 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction)
// FIXME: for offline player need also // FIXME: for offline player need also
bidder->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1); bidder->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1);
} }
else
RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! RemoveAItem(auction->itemGuidLow); // we have to remove the item, before we delete it !!
auction->itemGuidLow = 0; // pending list will not use guid data
// will delete item or place to receiver mail list // will delete item or place to receiver mail list
MailDraft(msgAuctionWonSubject.str(), msgAuctionWonBody.str()) MailDraft(msgAuctionWonSubject.str(), msgAuctionWonBody.str())
@ -168,8 +169,9 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction)
// receiver not exist // receiver not exist
else else
{ {
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", pItem->GetGUIDLow()); CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", auction->itemGuidLow);
RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! RemoveAItem(auction->itemGuidLow); // we have to remove the item, before we delete it !!
auction->itemGuidLow = 0;
delete pItem; delete pItem;
} }
} }
@ -269,8 +271,9 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry * auction)
if (owner) if (owner)
owner->GetSession()->SendAuctionOwnerNotification(auction); owner->GetSession()->SendAuctionOwnerNotification(auction);
else
RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! RemoveAItem(auction->itemGuidLow); // we have to remove the item, before we delete it !!
auction->itemGuidLow = 0;
// will delete item or place to receiver mail list // will delete item or place to receiver mail list
MailDraft(subject.str(), "") // TODO: fix body MailDraft(subject.str(), "") // TODO: fix body
@ -280,8 +283,9 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry * auction)
// owner not found // owner not found
else else
{ {
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'",pItem->GetGUIDLow()); CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", auction->itemGuidLow);
RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! RemoveAItem(auction->itemGuidLow); // we have to remove the item, before we delete it !!
auction->itemGuidLow = 0;
delete pItem; delete pItem;
} }
} }
@ -364,7 +368,7 @@ void AuctionHouseMgr::LoadAuctions()
return; return;
} }
result = CharacterDatabase.Query("SELECT id,houseid,itemguid,item_template,itemowner,buyoutprice,time,moneyTime,buyguid,lastbid,startbid,deposit FROM auction"); result = CharacterDatabase.Query("SELECT id,houseid,itemguid,item_template,item_count,item_randompropertyid,itemowner,buyoutprice,time,moneyTime,buyguid,lastbid,startbid,deposit FROM auction");
if (!result) if (!result)
{ {
BarGoLink bar(1); BarGoLink bar(1);
@ -390,7 +394,10 @@ void AuctionHouseMgr::LoadAuctions()
uint32 houseid = fields[1].GetUInt32(); uint32 houseid = fields[1].GetUInt32();
auction->itemGuidLow = fields[2].GetUInt32(); auction->itemGuidLow = fields[2].GetUInt32();
auction->itemTemplate = fields[3].GetUInt32(); auction->itemTemplate = fields[3].GetUInt32();
auction->owner = fields[4].GetUInt32(); auction->itemCount = fields[4].GetUInt32();
auction->itemRandomPropertyId = fields[5].GetUInt32();
auction->owner = fields[6].GetUInt32();
if (auction->owner) if (auction->owner)
{ {
@ -407,24 +414,43 @@ void AuctionHouseMgr::LoadAuctions()
auction->ownerName = plWName; auction->ownerName = plWName;
} }
auction->buyout = fields[5].GetUInt32(); auction->buyout = fields[7].GetUInt32();
auction->expireTime = fields[6].GetUInt32(); auction->expireTime = fields[8].GetUInt32();
auction->moneyDeliveryTime = fields[7].GetUInt32(); auction->moneyDeliveryTime = fields[9].GetUInt32();
auction->bidder = fields[8].GetUInt32(); auction->bidder = fields[10].GetUInt32();
auction->bid = fields[9].GetUInt32(); auction->bid = fields[11].GetUInt32();
auction->startbid = fields[10].GetUInt32(); auction->startbid = fields[12].GetUInt32();
auction->deposit = fields[11].GetUInt32(); auction->deposit = fields[13].GetUInt32();
auction->auctionHouseEntry = NULL; // init later auction->auctionHouseEntry = NULL; // init later
// check if sold item exists for guid if (auction->moneyDeliveryTime)
// and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems) auction->itemGuidLow = 0; // must be 0 if auction delivery pending
Item* pItem = GetAItem(auction->itemGuidLow); else
if (!pItem)
{ {
auction->DeleteFromDB(); // check if sold item exists for guid
sLog.outError("Auction %u has not a existing item : %u, deleted", auction->Id, auction->itemGuidLow); // and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems)
delete auction; Item* pItem = GetAItem(auction->itemGuidLow);
continue; if (!pItem)
{
auction->DeleteFromDB();
sLog.outError("Auction %u has not a existing item : %u, deleted", auction->Id, auction->itemGuidLow);
delete auction;
continue;
}
// overwrite by real item data
if ((auction->itemTemplate != pItem->GetEntry()) ||
(auction->itemCount != pItem->GetCount()) ||
(auction->itemRandomPropertyId != pItem->GetItemRandomPropertyId()))
{
auction->itemTemplate = pItem->GetEntry();
auction->itemCount = pItem->GetCount();
auction->itemRandomPropertyId = pItem->GetItemRandomPropertyId();
//No SQL injection (no strings)
CharacterDatabase.PExecute("UPDATE auction SET item_template = %u, item_count = %u, item_randompropertyid = %i WHERE itemguid = %u",
auction->itemTemplate, auction->itemCount, auction->itemRandomPropertyId, auction->itemGuidLow);
}
} }
auction->auctionHouseEntry = sAuctionHouseStore.LookupEntry(houseid); auction->auctionHouseEntry = sAuctionHouseStore.LookupEntry(houseid);
@ -438,12 +464,19 @@ void AuctionHouseMgr::LoadAuctions()
std::ostringstream msgAuctionCanceledOwner; std::ostringstream msgAuctionCanceledOwner;
msgAuctionCanceledOwner << auction->itemTemplate << ":0:" << AUCTION_CANCELED << ":0:0"; msgAuctionCanceledOwner << auction->itemTemplate << ":0:" << AUCTION_CANCELED << ":0:0";
// item will deleted or added to received mail list if (auction->itemGuidLow)
MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body {
.AddItem(pItem) Item* pItem = GetAItem(auction->itemGuidLow);
.SendMailTo(MailReceiver(ObjectGuid(HIGHGUID_PLAYER, auction->owner)), auction, MAIL_CHECK_MASK_COPIED);
RemoveAItem(auction->itemGuidLow);
auction->itemGuidLow = 0;
// item will deleted or added to received mail list
MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body
.AddItem(pItem)
.SendMailTo(MailReceiver(ObjectGuid(HIGHGUID_PLAYER, auction->owner)), auction, MAIL_CHECK_MASK_COPIED);
}
RemoveAItem(auction->itemGuidLow);
auction->DeleteFromDB(); auction->DeleteFromDB();
delete auction; delete auction;
@ -578,7 +611,7 @@ void AuctionHouseObject::Update()
sAuctionMgr.SendAuctionSuccessfulMail(itr->second); sAuctionMgr.SendAuctionSuccessfulMail(itr->second);
itr->second->DeleteFromDB(); itr->second->DeleteFromDB();
sAuctionMgr.RemoveAItem(itr->second->itemGuidLow); MANGOS_ASSERT(!itr->second->itemGuidLow); // already removed or send in mail at won
delete itr->second; delete itr->second;
RemoveAuction(itr->first); RemoveAuction(itr->first);
} }
@ -587,22 +620,17 @@ void AuctionHouseObject::Update()
{ {
if (curTime > itr->second->expireTime) if (curTime > itr->second->expireTime)
{ {
///- Either cancel the auction if there was no bidder ///- perform the transaction if there was bidder
if (itr->second->bidder == 0) if (itr->second->bidder)
{ {
sAuctionMgr.SendAuctionExpiredMail(itr->second); itr->second->AuctionBidWinning();
}
///- Or perform the transaction
else
{
itr->second->moneyDeliveryTime = time(NULL) + HOUR;
sAuctionMgr.SendAuctionWonMail(itr->second);
continue; continue;
} }
///- In any case clear the auction ///- cancel the auction if there was no bidder
sAuctionMgr.SendAuctionExpiredMail(itr->second);
itr->second->DeleteFromDB(); itr->second->DeleteFromDB();
sAuctionMgr.RemoveAItem(itr->second->itemGuidLow);
delete itr->second; delete itr->second;
RemoveAuction(itr->first); RemoveAuction(itr->first);
} }
@ -648,25 +676,25 @@ int AuctionEntry::CompareAuctionEntry(uint32 column, const AuctionEntry *auc, Pl
{ {
case 0: // level = 0 case 0: // level = 0
{ {
Item *item1 = sAuctionMgr.GetAItem(itemGuidLow); ItemPrototype const* itemProto1 = ObjectMgr::GetItemPrototype(itemTemplate);
Item *item2 = sAuctionMgr.GetAItem(auc->itemGuidLow); ItemPrototype const* itemProto2 = ObjectMgr::GetItemPrototype(auc->itemTemplate);
if (!item1 || !item2) if (!itemProto2 || !itemProto1)
return 0; return 0;
if (item1->GetProto()->RequiredLevel < item2->GetProto()->RequiredLevel) if (itemProto1->RequiredLevel < itemProto2->RequiredLevel)
return -1; return -1;
else if (item1->GetProto()->RequiredLevel > item2->GetProto()->RequiredLevel) else if (itemProto1->RequiredLevel > itemProto2->RequiredLevel)
return +1; return +1;
break; break;
} }
case 1: // quality = 1 case 1: // quality = 1
{ {
Item *item1 = sAuctionMgr.GetAItem(itemGuidLow); ItemPrototype const* itemProto1 = ObjectMgr::GetItemPrototype(itemTemplate);
Item *item2 = sAuctionMgr.GetAItem(auc->itemGuidLow); ItemPrototype const* itemProto2 = ObjectMgr::GetItemPrototype(auc->itemTemplate);
if (!item1 || !item2) if (!itemProto2 || !itemProto1)
return 0; return 0;
if (item1->GetProto()->Quality < item2->GetProto()->Quality) if (itemProto1->Quality < itemProto2->Quality)
return -1; return -1;
else if (item1->GetProto()->Quality > item2->GetProto()->Quality) else if (itemProto1->Quality > itemProto2->Quality)
return +1; return +1;
break; break;
} }
@ -765,13 +793,9 @@ int AuctionEntry::CompareAuctionEntry(uint32 column, const AuctionEntry *auc, Pl
break; break;
case 9: // quantity = 9 case 9: // quantity = 9
{ {
Item *item1 = sAuctionMgr.GetAItem(itemGuidLow); if (itemCount < auc->itemCount)
Item *item2 = sAuctionMgr.GetAItem(auc->itemGuidLow);
if (!item1 || !item2)
return 0;
if (item1->GetCount() < item2->GetCount())
return -1; return -1;
else if (item1->GetCount() > item2->GetCount()) else if (itemCount > auc->itemCount)
return +1; return +1;
break; break;
} }
@ -889,15 +913,8 @@ void AuctionHouseObject::BuildListPendingSales(WorldPacket& data, Player* player
continue; continue;
if (Aentry && Aentry->owner == player->GetGUIDLow()) if (Aentry && Aentry->owner == player->GetGUIDLow())
{ {
Item *pItem = sAuctionMgr.GetAItem(Aentry->itemGuidLow);
if (!pItem)
{
sLog.outError("Auction: item with guid %u doesn't exist!", Aentry->itemGuidLow);
continue;
}
std::ostringstream str1; std::ostringstream str1;
str1 << Aentry->itemTemplate << ":" << pItem->GetItemRandomPropertyId() << ":" << AUCTION_SUCCESSFUL << ":" << Aentry->Id << ":" << pItem->GetCount(); str1 << Aentry->itemTemplate << ":" << Aentry->itemRandomPropertyId << ":" << AUCTION_SUCCESSFUL << ":" << Aentry->Id << ":" << Aentry->itemCount;
std::ostringstream str2; std::ostringstream str2;
str2.width(16); str2.width(16);
@ -923,6 +940,8 @@ AuctionEntry* AuctionHouseObject::AddAuction(AuctionHouseEntry const* auctionHou
AH->Id = sObjectMgr.GenerateAuctionID(); AH->Id = sObjectMgr.GenerateAuctionID();
AH->itemGuidLow = newItem->GetObjectGuid().GetCounter(); AH->itemGuidLow = newItem->GetObjectGuid().GetCounter();
AH->itemTemplate = newItem->GetEntry(); AH->itemTemplate = newItem->GetEntry();
AH->itemCount = newItem->GetCount();
AH->itemRandomPropertyId = newItem->GetItemRandomPropertyId();
AH->owner = pl ? pl->GetGUIDLow() : 0; AH->owner = pl ? pl->GetGUIDLow() : 0;
if (pl) if (pl)
@ -1009,7 +1028,15 @@ void AuctionEntry::DeleteFromDB() const
void AuctionEntry::SaveToDB() const void AuctionEntry::SaveToDB() const
{ {
//No SQL injection (no strings) //No SQL injection (no strings)
CharacterDatabase.PExecute("INSERT INTO auction (id,houseid,itemguid,item_template,itemowner,buyoutprice,time,moneyTime,buyguid,lastbid,startbid,deposit) " CharacterDatabase.PExecute("INSERT INTO auction (id,houseid,itemguid,item_template,item_count,item_randompropertyid,itemowner,buyoutprice,time,moneyTime,buyguid,lastbid,startbid,deposit) "
"VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" UI64FMTD "', '" UI64FMTD "', '%u', '%u', '%u', '%u')", "VALUES ('%u', '%u', '%u', '%u', '%u', '%i', '%u', '%u', '" UI64FMTD "', '" UI64FMTD "', '%u', '%u', '%u', '%u')",
Id, auctionHouseEntry->houseId, itemGuidLow, itemTemplate, owner, buyout, (uint64)expireTime, (uint64)moneyDeliveryTime, bidder, bid, startbid, deposit); Id, auctionHouseEntry->houseId, itemGuidLow, itemTemplate, itemCount, itemRandomPropertyId, owner, buyout, (uint64)expireTime, (uint64)moneyDeliveryTime, bidder, bid, startbid, deposit);
}
void AuctionEntry::AuctionBidWinning()
{
moneyDeliveryTime = time(NULL) + HOUR;
CharacterDatabase.PExecute("UPDATE auction SET itemguid = 0, moneyTime = '" UI64FMTD "', buyguid = '%u', lastbid = '%u' WHERE id = '%u'", (uint64)moneyDeliveryTime, bidder, bid, Id);
sAuctionMgr.SendAuctionWonMail(this);
} }

View file

@ -56,8 +56,10 @@ enum AuctionAction
struct AuctionEntry struct AuctionEntry
{ {
uint32 Id; uint32 Id;
uint32 itemGuidLow; uint32 itemGuidLow; // can be 0 after send won mail with item
uint32 itemTemplate; uint32 itemTemplate;
uint32 itemCount;
int32 itemRandomPropertyId;
uint32 owner; // player low guid, can be 0 for server generated auction uint32 owner; // player low guid, can be 0 for server generated auction
std::wstring ownerName; // cache name for sorting std::wstring ownerName; // cache name for sorting
uint32 startbid; // maybe useless uint32 startbid; // maybe useless
@ -77,6 +79,8 @@ struct AuctionEntry
bool BuildAuctionInfo(WorldPacket & data) const; bool BuildAuctionInfo(WorldPacket & data) const;
void DeleteFromDB() const; void DeleteFromDB() const;
void SaveToDB() const; void SaveToDB() const;
void AuctionBidWinning();
// -1,0,+1 order result // -1,0,+1 order result
int CompareAuctionEntry(uint32 column, const AuctionEntry *auc, Player* viewPlayer) const; int CompareAuctionEntry(uint32 column, const AuctionEntry *auc, Player* viewPlayer) const;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "11703" #define REVISION_NR "11704"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__ #ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__ #define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_11620_01_characters_character_equipmentsets" #define REVISION_DB_CHARACTERS "required_11704_01_characters_auction"
#define REVISION_DB_MANGOS "required_11701_01_mangos_command" #define REVISION_DB_MANGOS "required_11701_01_mangos_command"
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
#endif // __REVISION_SQL_H__ #endif // __REVISION_SQL_H__