Here is a class you can use to dump out AH data with zero function calls or hooks.
Uses include:
Base for AH bot, getting 'hidden' info on auctions when at the AH (i.e. expire time), etc.
Credits to Bsing for CFindPattern and CLog.
AuctionHouse.h:
AuctionHouse.cppCode:#pragma once // C++ Standard Library #include <vector> // Forward declarations class WoWAuctionEntry; // Container to hold pointers to all the requested auction entries typedef std::vector<WoWAuctionEntry*> AuctionEntries; // Enchant info for the WoWAuctionEntry structure class WoWAucEnchantInfo { public: unsigned int EnchantID; unsigned int EnchantDuration; unsigned int EnchantCharges; }; // sizeof(AuctionEnchantInfo) == 0xC // Each auction on the page has one of these structures. Stored in an array. // Only 'list' page reversed so far. Unsure if structure is reused. // One array per type. class WoWAuctionEntry { public: unsigned int Unk00; // 0x00 unsigned int AuctionId; // 0x04 unsigned int ItemEntry; // 0x08 WoWAucEnchantInfo EnchantInfo[7]; // 0x0C unsigned int RandomPropertyID; // 0x60 unsigned int ItemSuffixFactor; // 0x64 unsigned int Count; // 0x68 unsigned int SpellCharges; // 0x6C unsigned int Unk70; // 0x70 unsigned int Unk74; // 0x74 unsigned int SellerGuidB; // 0x78 unsigned int SellerGuidA; // 0x7C unsigned int StartBid; // 0x80 unsigned int MinBidInc; // 0x84 unsigned int BuyOut; // 0x88 unsigned int ExpireTime; // 0x8C unsigned int BidderGuidB; // 0x90 unsigned int BidderGuidA; // 0x94 unsigned int CurrentBid; // 0x98 unsigned int SaleStatus; // 0x9C }; // sizeof(WoWAuctionEntry) = 0xA0 // Manager class for the AuctionHouse. User defined, not from WoW. class AuctionHouseMgr { public: // Enum for different types of AH lists enum AuctionListType { ListAuction, OwnerAuction, BidderAuction }; // Singleton static AuctionHouseMgr* Get(); // Get all auctions from a type AuctionEntries GetAuctions(AuctionListType Type); // Get number of auctions in the current page for a type unsigned int GetNumAuctions(AuctionListType Type); // Get the total number of auctions for a type unsigned int GetFullNumAuctions(AuctionListType Type); // Get number of pages of auctions for a type unsigned int GetNumPages(AuctionListType Type); protected: // Enforce usage of singleton AuctionHouseMgr(); ~AuctionHouseMgr(); AuctionHouseMgr(const AuctionHouseMgr&); AuctionHouseMgr& operator= (const AuctionHouseMgr&); private: // Singleton static AuctionHouseMgr* m_pAuctionHouseMgr; // Pointers to page count variables in WoW unsigned int* m_pNumListAuctions; unsigned int* m_pNumOwnerAuctions; unsigned int* m_pNumBidderAuctions; // Pointers to full count variables in WoW unsigned int* m_pFullNumListAuctions; unsigned int* m_pFullNumOwnerAuctions; unsigned int* m_pFullNumBidderAuctions; // Pointers to list arrays in WoW WoWAuctionEntry** m_pListAuctions; WoWAuctionEntry** m_pOwnerAuctions; WoWAuctionEntry** m_pBidderAuctions; };
Patterns:Code:// Red Pill #include "AuctionHouse.h" #include "RedPillMgr.h" #include "FindPattern.h" #include "Log.h" // C++ Standard Library #include <cmath> // Initialize static data AuctionHouseMgr* AuctionHouseMgr::m_pAuctionHouseMgr = 0; // Get singleton AuctionHouseMgr* AuctionHouseMgr::Get() { if (!m_pAuctionHouseMgr) m_pAuctionHouseMgr = new AuctionHouseMgr(); return m_pAuctionHouseMgr; } // Constructor AuctionHouseMgr::AuctionHouseMgr() { // Set all pointers at startup to avoid overhead of getting address from pattern scanner at runtime // on every call. m_pNumListAuctions = reinterpret_cast<unsigned int*>(RedPillMgr::Get()->GetFindPattern()->GetAddress("NumListAuctions")); m_pNumOwnerAuctions = reinterpret_cast<unsigned int*>(RedPillMgr::Get()->GetFindPattern()->GetAddress("NumOwnerAuctions")); m_pNumBidderAuctions = reinterpret_cast<unsigned int*>(RedPillMgr::Get()->GetFindPattern()->GetAddress("NumBidderAuctions")); m_pFullNumListAuctions = reinterpret_cast<unsigned int*>(RedPillMgr::Get()->GetFindPattern()->GetAddress("FullNumListAuctions")); m_pFullNumOwnerAuctions = reinterpret_cast<unsigned int*>(RedPillMgr::Get()->GetFindPattern()->GetAddress("FullNumOwnerAuctions")); m_pFullNumBidderAuctions = reinterpret_cast<unsigned int*>(RedPillMgr::Get()->GetFindPattern()->GetAddress("FullNumBidderAuctions")); m_pListAuctions = reinterpret_cast<WoWAuctionEntry**>(RedPillMgr::Get()->GetFindPattern()->GetAddress("ListAuctions")); m_pOwnerAuctions = reinterpret_cast<WoWAuctionEntry**>(RedPillMgr::Get()->GetFindPattern()->GetAddress("OwnerAuctions")); m_pBidderAuctions = reinterpret_cast<WoWAuctionEntry**>(RedPillMgr::Get()->GetFindPattern()->GetAddress("BidderAuctions")); } // Get number of auctions on current page for a type unsigned int AuctionHouseMgr::GetNumAuctions(AuctionListType Type) { // Return value unsigned int Count = 0; // Get count switch (Type) { case ListAuction: Count = *m_pNumListAuctions; break; case OwnerAuction: Count = *m_pNumOwnerAuctions; break; case BidderAuction: Count = *m_pNumBidderAuctions; break; default: break; } // Debug output DBGLOG("[AuctionHouseMgr]: NumAuctions requested. Type: " << Type << ". Count: " << Count << "."); return Count; } // Get total number of auctions for a type unsigned int AuctionHouseMgr::GetFullNumAuctions(AuctionListType Type) { // Return value unsigned int Count = 0; // Get count switch (Type) { case ListAuction: Count = *m_pFullNumListAuctions; break; case OwnerAuction: Count = *m_pFullNumOwnerAuctions; break; case BidderAuction: Count = *m_pFullNumBidderAuctions; break; default: break; } // Debug info DBGLOG("[AuctionHouseMgr]: FullNumAuctions requested. Type: " << Type << ". Count: " << Count << "."); return Count; } // Get all the auctions for a current type AuctionEntries AuctionHouseMgr::GetAuctions(AuctionListType Type) { // Return value AuctionEntries Auctions; // Number of auctions for requested type unsigned int NumAuctions = 0; // Array pointer for requested type WoWAuctionEntry* pAuctions = 0; // Get pointers for requested type switch (Type) { case ListAuction: NumAuctions = *m_pNumListAuctions; pAuctions = *m_pListAuctions; break; case OwnerAuction: NumAuctions = *m_pNumOwnerAuctions; pAuctions = *m_pOwnerAuctions; break; case BidderAuction: NumAuctions = *m_pNumBidderAuctions; pAuctions = *m_pBidderAuctions; break; default: break; } // Ensure data is valid if (!NumAuctions || !pAuctions) return Auctions; // Enumerate array and push back pointers to each array entry for (unsigned int i = 1; i <= NumAuctions; ++i) Auctions.push_back(&pAuctions[i-1]); // Debug output DBGLOG("[AuctionHouseMgr]: Auctions requested. Type: " << Type << "Count: " << Auctions.size() << "."); return Auctions; } // Get number of pages for a type unsigned int AuctionHouseMgr::GetNumPages(AuctionListType Type) { // Count. Double due to division and rounding. double Count = 0; // Get count switch (Type) { case ListAuction: Count = (*m_pFullNumListAuctions > 50) ? (*m_pFullNumListAuctions / 50) : (1); break; case OwnerAuction: Count = (*m_pFullNumOwnerAuctions > 50) ? (*m_pFullNumOwnerAuctions / 50) : (1); break; case BidderAuction: Count = (*m_pFullNumBidderAuctions > 50) ? (*m_pFullNumBidderAuctions / 50) : (1); break; default: break; } // Return value. Round up because even one extra auction counts as a // whole extra page. unsigned int RetCount = static_cast<unsigned int>(ceil(Count)); // Debug output. DBGLOG("[AuctionHouseMgr]: NumPages requested. Type: " << Type << ". Count: " << RetCount << "."); return RetCount; }
Address:Code:<Pattern desc="ListAuctions" pattern="\x8B\x0D\x00\x00\x00\x00\x8D\x04\x80\xC1\xE0\x00\x8B\x54\x08\x00\x89\x15" mask="xx????xxxxx?xxx?xx"> <Add value="2"/> <Lea/> </Pattern> <Pattern desc="OwnerAuctions" start="ListAuctions" pattern="\x00" mask="?"> <Add value="F"/> </Pattern> <Pattern desc="BidderAuctions" start="ListAuctions" pattern="\x00" mask="?"> <Add value="1F"/> </Pattern> <Pattern desc="FullNumListAuctions" pattern="\x8B\x45\x00\x83\xC0\x00\x81\xC6\x00\x00\x00\x00\x3B\x45\x00\x89\x45\x00\x0F\x82" mask="xx?xx?xx????xx?xx?xx"> <Add value="1A"/> <Lea/> </Pattern> <Pattern desc="FullNumOwnerAuctions" start="FullNumListAuctions" pattern="\x00" mask="?"> <Add value="3"/> </Pattern> <Pattern desc="FullNumBidderAuctions" start="FullNumListAuctions" pattern="\x00" mask="?"> <Add value="7"/> </Pattern> <Pattern desc="NumListAuctions" pattern="\x73\x00\x8B\x0D\x00\x00\x00\x00\x8D\x04\x80\xC1\xE0\x00\x8B\x54\x08\" mask="x?xx????xxxxx?xxx"> <Sub value="4"/> <Lea/> </Pattern> <Pattern desc="NumOwnerAuctions" start="NumListAuctions" pattern="\x00" mask="?"> <Add value="F"/> </Pattern> <Pattern desc="NumBidderAuctions" start="NumListAuctions" pattern="\x00" mask="?"> <Add value="1F"/> </Pattern>
Example Usage:Code:[13:24:53]: [FindPattern]: 0x01163FF0 -> ListAuctions [13:24:53]: [FindPattern]: 0x01164000 -> OwnerAuctions [13:24:53]: [FindPattern]: 0x01164010 -> BidderAuctions [13:24:53]: [FindPattern]: 0x01163FB4 -> FullNumListAuctions [13:24:53]: [FindPattern]: 0x01163FB8 -> FullNumOwnerAuctions [13:24:53]: [FindPattern]: 0x01163FBC -> FullNumBidderAuctions [13:24:53]: [FindPattern]: 0x01163FEC -> NumListAuctions [13:24:53]: [FindPattern]: 0x01163FFC -> NumOwnerAuctions [13:24:53]: [FindPattern]: 0x0116400C -> NumBidderAuctions
Screenshot:Code:// Callback for the 'dumpauc' console command void CEGUIConsole::DumpAucCallback(const std::string& Params) { AuctionEntries Auctions; if (Params == "list") Auctions = AuctionHouseMgr::Get()->GetAuctions(AuctionHouseMgr::ListAuction); else if (Params == "owner") Auctions = AuctionHouseMgr::Get()->GetAuctions(AuctionHouseMgr::OwnerAuction); else if (Params == "bidder") Auctions = AuctionHouseMgr::Get()->GetAuctions(AuctionHouseMgr::BidderAuction); else WriteOutput("[DumpAuc]: Error. Invalid auction type. Valid types are 'list', 'owner', and 'auction'"); for (AuctionEntries::size_type i = 0; i < Auctions.size(); i++) { WoWAuctionEntry* pEntry = Auctions[i]; DBGLOG(boost::str(boost::format("[DumpAuc]: Type: %s, Number: %u") %Params %i)); DBGLOG(boost::str(boost::format("[DumpAuc]: Unk00: %u") %pEntry->Unk00)); DBGLOG(boost::str(boost::format("[DumpAuc]: AuctionId: %u") %pEntry->AuctionId)); DBGLOG(boost::str(boost::format("[DumpAuc]: ItemEntry: %u") %pEntry->ItemEntry)); for (int c = 0; c < 7; c++) { DBGLOG(boost::str(boost::format("[DumpAuc]: EnchantID%u: %u") %c %pEntry->EnchantInfo[c].EnchantID)); DBGLOG(boost::str(boost::format("[DumpAuc]: EnchantDuration%u: %u") %c %pEntry->EnchantInfo[c].EnchantDuration)); DBGLOG(boost::str(boost::format("[DumpAuc]: EnchantCharges%u: %u") %c %pEntry->EnchantInfo[c].EnchantCharges)); } DBGLOG(boost::str(boost::format("[DumpAuc]: RandomPropertyID: %u") %pEntry->RandomPropertyID)); DBGLOG(boost::str(boost::format("[DumpAuc]: ItemSuffixFactor: %u") %pEntry->ItemSuffixFactor)); DBGLOG(boost::str(boost::format("[DumpAuc]: Count: %u") %pEntry->Count)); DBGLOG(boost::str(boost::format("[DumpAuc]: SpellCharges: %u") %pEntry->SpellCharges)); DBGLOG(boost::str(boost::format("[DumpAuc]: Unk70: %u") %pEntry->Unk70)); DBGLOG(boost::str(boost::format("[DumpAuc]: Unk74: %u") %pEntry->Unk74)); DBGLOG(boost::str(boost::format("[DumpAuc]: SellerGuidB: %08X") %pEntry->SellerGuidB)); DBGLOG(boost::str(boost::format("[DumpAuc]: SellerGuidA: %08X") %pEntry->SellerGuidA)); DBGLOG(boost::str(boost::format("[DumpAuc]: StartBid: %u") %pEntry->StartBid)); DBGLOG(boost::str(boost::format("[DumpAuc]: MinBidInc: %u") %pEntry->MinBidInc)); DBGLOG(boost::str(boost::format("[DumpAuc]: BuyOut: %u") %pEntry->BuyOut)); DBGLOG(boost::str(boost::format("[DumpAuc]: ExpireTime: %u") %pEntry->ExpireTime)); DBGLOG(boost::str(boost::format("[DumpAuc]: BidderGuidB: %08X") %pEntry->BidderGuidB)); DBGLOG(boost::str(boost::format("[DumpAuc]: BidderGuidA: %08X") %pEntry->BidderGuidA)); DBGLOG(boost::str(boost::format("[DumpAuc]: CurrentBid: %u") %pEntry->CurrentBid)); DBGLOG(boost::str(boost::format("[DumpAuc]: SaleStatus: %u") %pEntry->SaleStatus)); } } // Callback for the 'auc' console command void CEGUIConsole::AucCallback(const std::string& Params) { std::stringstream ParamStream(Params); std::string Type; unsigned int Num; ParamStream >> Type >> Num; AuctionEntries Auctions; if (Type == "list") Auctions = AuctionHouseMgr::Get()->GetAuctions(AuctionHouseMgr::ListAuction); else if (Type == "owner") Auctions = AuctionHouseMgr::Get()->GetAuctions(AuctionHouseMgr::OwnerAuction); else if (Type == "bidder") Auctions = AuctionHouseMgr::Get()->GetAuctions(AuctionHouseMgr::BidderAuction); else { WriteOutput("[DumpAuc]: Error. Invalid auction type. Valid types are 'list', 'owner', and 'auction'"); return; } if (Num > Auctions.size()) { WriteOutput("[Auc]: Error. Invalid auction number."); return; } unsigned int i = Num-1; WoWAuctionEntry* pEntry = Auctions[i]; WriteOutput(boost::str(boost::format("[Auc]: Type: %s, Number: %u") %Params %i)); WriteOutput(boost::str(boost::format("[Auc]: Unk00: %u") %pEntry->Unk00)); WriteOutput(boost::str(boost::format("[Auc]: AuctionId: %u") %pEntry->AuctionId)); WriteOutput(boost::str(boost::format("[Auc]: ItemEntry: %u") %pEntry->ItemEntry)); for (int c = 0; c < 7; c++) { WriteOutput(boost::str(boost::format("[Auc]: EnchantID%u: %u") %c %pEntry->EnchantInfo[c].EnchantID)); WriteOutput(boost::str(boost::format("[Auc]: EnchantDuration%u: %u") %c %pEntry->EnchantInfo[c].EnchantDuration)); WriteOutput(boost::str(boost::format("[Auc]: EnchantCharges%u: %u") %c %pEntry->EnchantInfo[c].EnchantCharges)); } WriteOutput(boost::str(boost::format("[Auc]: RandomPropertyID: %u") %pEntry->RandomPropertyID)); WriteOutput(boost::str(boost::format("[Auc]: ItemSuffixFactor: %u") %pEntry->ItemSuffixFactor)); WriteOutput(boost::str(boost::format("[Auc]: Count: %u") %pEntry->Count)); WriteOutput(boost::str(boost::format("[Auc]: SpellCharges: %u") %pEntry->SpellCharges)); WriteOutput(boost::str(boost::format("[Auc]: Unk70: %u") %pEntry->Unk70)); WriteOutput(boost::str(boost::format("[Auc]: Unk74: %u") %pEntry->Unk74)); WriteOutput(boost::str(boost::format("[Auc]: SellerGuid: %08X%08X") %pEntry->SellerGuidA %pEntry->SellerGuidB)); WriteOutput(boost::str(boost::format("[Auc]: StartBid: %u") %pEntry->StartBid)); WriteOutput(boost::str(boost::format("[Auc]: MinBidInc: %u") %pEntry->MinBidInc)); WriteOutput(boost::str(boost::format("[Auc]: BuyOut: %u") %pEntry->BuyOut)); WriteOutput(boost::str(boost::format("[Auc]: ExpireTime: %u") %pEntry->ExpireTime)); WriteOutput(boost::str(boost::format("[Auc]: BidderGuid: %08X%08X") %pEntry->BidderGuidA %pEntry->BidderGuidB)); WriteOutput(boost::str(boost::format("[Auc]: CurrentBid: %u") %pEntry->CurrentBid)); WriteOutput(boost::str(boost::format("[Auc]: SaleStatus: %u") %pEntry->SaleStatus)); }
Notes:
a) The timestamp for expiretime will match up with the one given by OsGetAsyncTimeMs (e.g GetTickCount, QueryPerformanceCounter, etc depending on your timingMethod).
c) I probably missed or overlooked something but whatever. Have fun!
If anyone reverses more of the auctionentry structure please post here because I'm lazy.