diff --git a/src/framework/Platform/Define.h b/src/framework/Platform/Define.h index 3ce41eab3..ec70a2e5a 100644 --- a/src/framework/Platform/Define.h +++ b/src/framework/Platform/Define.h @@ -127,4 +127,19 @@ typedef uint32 DWORD; typedef uint64 OBJECT_HANDLE; +enum +{ + FT_NA = 'x', // ignore/ default, 4 byte size, in Source String means field is ignored, in Dest String means field is filled with default value + FT_NA_BYTE = 'X', // ignore/ default, 1 byte size, see above + FT_NA_FLOAT = 'F', // ignore/ default, float size, see above + FT_NA_POINTER = 'p', // fill default value into dest, pointer size, Use this only with static data (otherwise mem-leak) + FT_STRING = 's', // char* + FT_FLOAT = 'f', // float + FT_INT = 'i', // uint32 + FT_BYTE = 'b', // uint8 + FT_SORT = 'd', // sorted by this field, field is not included + FT_IND = 'n', // the same,but parsed to data + FT_LOGIC = 'l' // Logical (boolean) +}; + #endif // MANGOS_DEFINE_H diff --git a/src/game/DB2Stores.cpp b/src/game/DB2Stores.cpp new file mode 100644 index 000000000..67cf8c0d5 --- /dev/null +++ b/src/game/DB2Stores.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005-2012 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DB2Stores.h" +#include "DBCStores.h" +#include "Policies/SingletonImp.h" +#include "Log.h" +#include "ProgressBar.h" +#include "SharedDefines.h" +#include "ObjectGuid.h" + +#include "DB2fmt.h" + +#include + +DB2Storage sItemStore(Itemfmt); +DB2Storage sItemCurrencyCostStore(ItemCurrencyCostfmt); +DB2Storage sItemExtendedCostStore(ItemExtendedCostEntryfmt); + +typedef std::list StoreProblemList1; +uint32 DB2FileCount = 0; + +static bool LoadDB2_assert_print(uint32 fsize,uint32 rsize, const std::string& filename) +{ + sLog.outError("Size of '%s' setted by format string (%u) not equal size of C++ structure (%u).",filename.c_str(),fsize,rsize); + + // ASSERT must fail after function call + return false; +} + +struct LocalDB2Data +{ + LocalDB2Data(LocaleConstant loc) + : defaultLocale(loc), availableDb2Locales(0xFFFFFFFF) {} + + LocaleConstant defaultLocale; + + // bitmasks for index of fullLocaleNameList + uint32 availableDb2Locales; +}; + +template +inline void LoadDB2(LocalDB2Data& localeData, StoreProblemList1& errors, DB2Storage& storage, std::string const& db2Path, std::string const& filename) +{ + // compatibility format and C++ structure sizes + MANGOS_ASSERT(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDB2_assert_print(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename)); + + ++DB2FileCount; + std::string db2Filename = db2Path + filename; + if (storage.Load(db2Filename.c_str(), localeData.defaultLocale)) + { + for(uint8 i = 0; fullLocaleNameList[i].name; ++i) + { + if (!(localeData.availableDb2Locales & (1 << i))) + continue; + + LocaleNameStr const* localStr = &fullLocaleNameList[i]; + + std::string db2_dir_loc = db2Path + localStr->name + "/"; + + std::string localizedName = db2Path + localStr->name + "/" + filename; + if(!storage.LoadStringsFrom(localizedName.c_str(), localStr->locale)) + localeData.availableDb2Locales &= ~(1<locale)); + + LoadDB2(availableDb2Locales,bad_db2_files,sItemStore, db2Path,"Item.db2"); + LoadDB2(availableDb2Locales,bad_db2_files,sItemCurrencyCostStore, db2Path,"ItemCurrencyCost.db2"); + LoadDB2(availableDb2Locales,bad_db2_files,sItemExtendedCostStore, db2Path,"ItemExtendedCost.db2"); + + // error checks + if (bad_db2_files.size() >= DB2FileCount) + { + sLog.outError("Incorrect DataDir value in worldserver.conf or ALL required *.db2 files (%d) not found by path: %sdb2", DB2FileCount, dataPath.c_str()); + exit(1); + } + else if (!bad_db2_files.empty()) + { + std::string str; + for (StoreProblemList1::iterator i = bad_db2_files.begin(); i != bad_db2_files.end(); ++i) + str += *i + "\n"; + + sLog.outError("Some required *.db2 files (%u from %d) not found or not compatible:\n%s",(uint32)bad_db2_files.size(), DB2FileCount, str.c_str()); + exit(1); + } + + // Check loaded DBC files proper version + if (!sItemStore.LookupEntry(68815) || // last client known item added in 4.2.0 + !sItemExtendedCostStore.LookupEntry(3652)) // last item extended cost added in 4.2.0 + { + sLog.outString(""); + sLog.outError("Please extract correct db2 files from build %s", AcceptableClientBuildsListStr().c_str()); + exit(1); + } + + sLog.outString(); + sLog.outString( ">> Initialized %d db2 stores", DB2FileCount ); +} diff --git a/src/game/DB2Stores.h b/src/game/DB2Stores.h new file mode 100644 index 000000000..e2affd526 --- /dev/null +++ b/src/game/DB2Stores.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005-2012 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MANGOS_DB2STORES_H +#define MANGOS_DB2STORES_H + +#include "Common.h" +#include "Database/DB2Store.h" +#include "DB2Structure.h" + +#include + +extern DB2Storage sItemStore; +extern DB2Storage sItemCurrencyCostStore; +extern DB2Storage sItemExtendedCostStore; + +void LoadDB2Stores(const std::string& dataPath); + +DB2Storage const* GetItemDisplayStore(); + +#endif diff --git a/src/game/DB2Structure.h b/src/game/DB2Structure.h new file mode 100644 index 000000000..721141de4 --- /dev/null +++ b/src/game/DB2Structure.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005-2012 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MANGOS_DB2STRUCTURE_H +#define MANGOS_DB2STRUCTURE_H + +#include "Common.h" +#include "DBCEnums.h" +#include "Path.h" +#include "Platform/Define.h" + +#include +#include +#include + +// Structures using to access raw DB2 data and required packing to portability +struct ItemEntry +{ + uint32 ID; // 0 + uint32 Class; // 1 + uint32 SubClass; // 2 + int32 Unk0; // 3 + int32 Material; // 4 + uint32 DisplayId; // 5 + uint32 InventoryType; // 6 + uint32 Sheath; // 7 +}; + +struct ItemCurrencyCostEntry +{ + //uint32 id; // 0 + uint32 itemid; // 1 +}; + +#define MAX_EXTENDED_COST_ITEMS 5 +#define MAX_EXTENDED_COST_CURRENCIES 5 + +struct ItemExtendedCostEntry +{ + uint32 Id; // 0 + uint32 reqhonorpoints; // 1 m_honorPoints + uint32 reqarenapoints; // 2 m_arenaPoints + uint32 reqarenaslot; // 3 m_arenaBracket + uint32 reqitem[MAX_EXTENDED_COST_ITEMS]; // 5-8 m_itemID + uint32 reqitemcount[MAX_EXTENDED_COST_ITEMS]; // 9-13 m_itemCount + uint32 reqpersonalarenarating; // 14 m_requiredArenaRating + //uint32 // 15 m_itemPurchaseGroup + uint32 reqcur[MAX_EXTENDED_COST_CURRENCIES]; // 16-20 + uint32 reqcurrcount[MAX_EXTENDED_COST_CURRENCIES]; // 21-25 + //uint32 something[5]; // 26-30 +}; + +#endif diff --git a/src/game/DB2fmt.h b/src/game/DB2fmt.h new file mode 100644 index 000000000..33300528f --- /dev/null +++ b/src/game/DB2fmt.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2005-2012 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MANGOS_DB2SFRM_H +#define MANGOS_DB2SFRM_H + +const char Itemfmt[]="niiiiiii"; +const char ItemCurrencyCostfmt[]="di"; +const char ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiiixiiiiiiiiiixxxxx"; + +#endif diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index bb16b9fd4..0097a23b2 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -28,6 +28,8 @@ #include "Group.h" #include "SocialMgr.h" #include "Util.h" +#include "DB2Structure.h" +#include "DB2Stores.h" /* differeces from off: -you can uninvite yourself - is is useful diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 2427a2bad..445d46de9 100755 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -45,6 +45,8 @@ #include "GossipDef.h" #include "Mail.h" #include "InstanceData.h" +#include "DB2Structure.h" +#include "DB2Stores.h" #include @@ -9075,7 +9077,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 return false; } - /*if (ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) + if (ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) { if (pl) ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST, ExtendedCost); @@ -9083,7 +9085,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 sLog.outErrorDb("Table `%s` contain item (Entry: %u) with wrong ExtendedCost (%u) for %s %u, ignoring", tableName, item_id, ExtendedCost, idStr, vendor_entry); return false; - }*/ + } if (maxcount > 0 && incrtime == 0) { diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 7995235ce..22e2776a9 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -62,6 +62,7 @@ #include "Mail.h" #include "SpellAuras.h" #include "DBCStores.h" +#include "DB2Stores.h" #include "SQLStorages.h" #include @@ -19285,7 +19286,7 @@ void Player::InitDisplayIds() } } -/*void Player::TakeExtendedCost(uint32 extendedCostId, uint32 count) +void Player::TakeExtendedCost(uint32 extendedCostId, uint32 count) { ItemExtendedCostEntry const* extendedCost = sItemExtendedCostStore.LookupEntry(extendedCostId); @@ -19299,7 +19300,7 @@ void Player::InitDisplayIds() if (extendedCost->reqitem[i]) DestroyItemCount(extendedCost->reqitem[i], extendedCost->reqitemcount[i] * count, true); } -}*/ +} // Return true is the bought item has a max count to force refresh of window by caller bool Player::BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot) @@ -19384,7 +19385,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uin return false; } - /*if (uint32 extendedCostId = crItem->ExtendedCost) + if (uint32 extendedCostId = crItem->ExtendedCost) { ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(extendedCostId); if (!iece) @@ -19424,7 +19425,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uin SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, NULL, NULL); return false; } - }*/ + } uint32 price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAG2_EXT_COST_REQUIRES_GOLD) ? pProto->BuyPrice * count : 0; @@ -19452,8 +19453,8 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uin ModifyMoney(-int32(price)); - /*if (crItem->ExtendedCost) - TakeExtendedCost(crItem->ExtendedCost, count);*/ + if (crItem->ExtendedCost) + TakeExtendedCost(crItem->ExtendedCost, count); pItem = StoreNewItem(dest, item, true); } @@ -19475,8 +19476,8 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uin ModifyMoney(-int32(price)); - /*if (crItem->ExtendedCost) - TakeExtendedCost(crItem->ExtendedCost, count);*/ + if (crItem->ExtendedCost) + TakeExtendedCost(crItem->ExtendedCost, count); pItem = EquipNewItem(dest, item, true); diff --git a/src/game/Player.h b/src/game/Player.h index e99e02a0e..3825c57cb 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1282,7 +1282,7 @@ class MANGOS_DLL_SPEC Player : public Unit Item* GetItemFromBuyBackSlot(uint32 slot); void RemoveItemFromBuyBackSlot(uint32 slot, bool del); - //void TakeExtendedCost(uint32 extendedCostId, uint32 count); + void TakeExtendedCost(uint32 extendedCostId, uint32 count); uint32 GetMaxKeyringSize() const { return KEYRING_SLOT_END - KEYRING_SLOT_START; } void SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2 = NULL, uint32 itemid = 0) const; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 38edc3946..ddc06e6ec 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -44,6 +44,7 @@ #include "BattleGround.h" #include "Util.h" #include "Chat.h" +#include "DB2Stores.h" extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; diff --git a/src/game/World.cpp b/src/game/World.cpp index 8329995c1..2373e26ad 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -42,6 +42,7 @@ #include "SpellMgr.h" #include "Chat.h" #include "DBCStores.h" +#include "DB2Stores.h" #include "MassMailMgr.h" #include "LootMgr.h" #include "ItemEnchantmentMgr.h" @@ -951,6 +952,7 @@ void World::SetInitialWorldSettings() ///- Load the DBC files sLog.outString("Initialize data stores..."); LoadDBCStores(m_dataPath); + LoadDB2Stores(m_dataPath); DetectDBCLang(); sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) diff --git a/src/shared/Database/DB2FileLoader.cpp b/src/shared/Database/DB2FileLoader.cpp new file mode 100644 index 000000000..beb6e2848 --- /dev/null +++ b/src/shared/Database/DB2FileLoader.cpp @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2005-2012 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "DB2FileLoader.h" + +DB2FileLoader::DB2FileLoader() +{ + data = NULL; + fieldsOffset = NULL; +} + +bool DB2FileLoader::Load(const char *filename, const char *fmt) +{ + uint32 header = 48; + if(data) + { + delete [] data; + data=NULL; + } + + FILE * f = fopen(filename, "rb"); + if(!f)return false; + + if(fread(&header, 4, 1, f) != 1) // Signature + { + fclose(f); + return false; + } + + EndianConvert(header); + + if(header != 0x32424457) + { + fclose(f); + return false; //'WDB2' + } + + if(fread(&recordCount,4,1,f)!=1) // Number of records + { + fclose(f); + return false; + } + + EndianConvert(recordCount); + + if(fread(&fieldCount,4,1,f)!=1) // Number of fields + { + fclose(f); + return false; + } + + EndianConvert(fieldCount); + + if(fread(&recordSize,4,1,f)!=1) // Size of a record + { + fclose(f); + return false; + } + + EndianConvert(recordSize); + + if(fread(&stringSize,4,1,f)!=1) // String size + { + fclose(f); + return false; + } + + EndianConvert(stringSize); + + /* NEW WDB2 FIELDS*/ + if(fread(&tableHash,4,1,f)!=1) // Table hash + { + fclose(f); + return false; + } + + EndianConvert(tableHash); + + if(fread(&build,4,1,f)!=1) // Build + { + fclose(f); + return false; + } + + EndianConvert(build); + + if(fread(&unk1,4,1,f)!=1) // Unknown WDB2 + { + fclose(f); + return false; + } + + EndianConvert(unk1); + + if(fread(&unk2,4,1,f)!=1) // Unknown WDB2 + { + fclose(f); + return false; + } + + EndianConvert(unk2); + + if(fread(&unk3,4,1,f)!=1) // Unknown WDB2 + { + fclose(f); + return false; + } + + EndianConvert(unk3); + + if(fread(&locale,4,1,f)!=1) // Locales + { + fclose(f); + return false; + } + + EndianConvert(locale); + + if(fread(&unk5,4,1,f)!=1) // Unknown WDB2 + { + fclose(f); + return false; + } + + EndianConvert(unk5); + + fieldsOffset = new uint32[fieldCount]; + fieldsOffset[0] = 0; + for(uint32 i = 1; i < fieldCount; i++) + { + fieldsOffset[i] = fieldsOffset[i - 1]; + if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields + fieldsOffset[i] += 1; + else // 4 byte fields (int32/float/strings) + fieldsOffset[i] += 4; + } + + data = new unsigned char[recordSize*recordCount+stringSize]; + stringTable = data + recordSize*recordCount; + + if(fread(data, recordSize * recordCount + stringSize, 1, f) != 1) + { + fclose(f); + return false; + } + + fclose(f); + return true; +} + +DB2FileLoader::~DB2FileLoader() +{ + if(data) + delete [] data; + if(fieldsOffset) + delete [] fieldsOffset; +} + +DB2FileLoader::Record DB2FileLoader::getRecord(size_t id) +{ + assert(data); + return Record(*this, data + id*recordSize); +} + +uint32 DB2FileLoader::GetFormatRecordSize(const char * format,int32* index_pos) +{ + uint32 recordsize = 0; + int32 i = -1; + for(uint32 x = 0; format[x]; ++ x) + { + switch(format[x]) + { + case FT_FLOAT: + recordsize += sizeof(float); + break; + case FT_INT: + recordsize += sizeof(uint32); + break; + case FT_STRING: + recordsize += sizeof(char*); + break; + case FT_SORT: + i=x; + break; + case FT_IND: + i=x; + recordsize += sizeof(uint32); + break; + case FT_BYTE: + recordsize += sizeof(uint8); + break; + case FT_LOGIC: + assert(false && "2 files not have logic field type"); + break; + case FT_NA: + case FT_NA_BYTE: + break; + default: + assert(false && "unknown format character"); + break; + } + } + + if (index_pos) + *index_pos = i; + + return recordsize; +} + +uint32 DB2FileLoader::GetFormatStringsFields(const char * format) +{ + uint32 stringfields = 0; + for(uint32 x=0; format[x];++x) + if (format[x] == FT_STRING) + ++stringfields; + + return stringfields; +} + +char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable) +{ + /* + format STRING, NA, FLOAT,NA,INT <=> + struct{ + char* field0, + float field1, + int field2 + }entry; + + this func will generate entry[rows] data; + */ + + typedef char * ptr; + if(strlen(format)!=fieldCount) + return NULL; + + //get struct size and index pos + int32 i; + uint32 recordsize=GetFormatRecordSize(format,&i); + + if(i>=0) + { + uint32 maxi=0; + //find max index + for(uint32 y=0;ymaxi)maxi=ind; + } + + ++maxi; + records=maxi; + indexTable=new ptr[maxi]; + memset(indexTable,0,maxi*sizeof(ptr)); + } + else + { + records = recordCount; + indexTable = new ptr[recordCount]; + } + + char* dataTable= new char[recordCount*recordsize]; + + uint32 offset=0; + + for(uint32 y =0; y < recordCount; ++y) + { + if (i >= 0) + { + indexTable[getRecord(y).getUInt(i)]=&dataTable[offset]; + } + else + indexTable[y]=&dataTable[offset]; + + for(uint32 x = 0; x < fieldCount; ++x) + { + switch(format[x]) + { + case FT_FLOAT: + *((float*)(&dataTable[offset]))=getRecord(y).getFloat(x); + offset += sizeof(float); + break; + case FT_IND: + case FT_INT: + *((uint32*)(&dataTable[offset]))=getRecord(y).getUInt(x); + offset += sizeof(uint32); + break; + case FT_BYTE: + *((uint8*)(&dataTable[offset]))=getRecord(y).getUInt8(x); + offset += sizeof(uint8); + break; + case FT_STRING: + *((char**)(&dataTable[offset]))=NULL; // will be replaces non-empty or "" strings in AutoProduceStrings + offset += sizeof(char*); + break; + case FT_LOGIC: + assert(false && "DBC files not have logic field type"); + break; + case FT_NA: + case FT_NA_BYTE: + case FT_SORT: + break; + default: + assert(false && "unknown format character"); + break; + } + } + } + + return dataTable; +} + +static char const* const nullStr = ""; + +char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* dataTable) +{ + if(strlen(format)!=fieldCount) + return NULL; + + // we store flat holders pool as single memory block + size_t stringFields = GetFormatStringsFields(format); + // each string field at load have array of string for each locale + size_t stringHolderSize = sizeof(char*) * MAX_LOCALE; + size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize; + size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount; + + char* stringHoldersPool= new char[stringHoldersPoolSize]; + + // dbc strings expected to have at least empty string + for(size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) + ((char const**)stringHoldersPool)[i] = nullStr; + + uint32 offset=0; + + // assign string holders to string field slots + for(uint32 y =0;y + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DB2_FILE_LOADER_H +#define DB2_FILE_LOADER_H + +#include "Platform/Define.h" +#include "Utilities/ByteConverter.h" +#include "Common.h" +#include + +class DB2FileLoader +{ + public: + DB2FileLoader(); + ~DB2FileLoader(); + + bool Load(const char *filename, const char *fmt); + + class Record + { + public: + float getFloat(size_t field) const + { + assert(field < file.fieldCount); + float val = *reinterpret_cast(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint32 getUInt(size_t field) const + { + assert(field < file.fieldCount); + uint32 val = *reinterpret_cast(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint8 getUInt8(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast(offset+file.GetOffset(field)); + } + + const char *getString(size_t field) const + { + assert(field < file.fieldCount); + size_t stringOffset = getUInt(field); + assert(stringOffset < file.stringSize); + return reinterpret_cast(file.stringTable + stringOffset); + } + + private: + Record(DB2FileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) {} + unsigned char *offset; + DB2FileLoader &file; + + friend class DB2FileLoader; + + }; + + // Get record by id + Record getRecord(size_t id); + /// Get begin iterator over records + + uint32 GetNumRows() const { return recordCount;} + uint32 GetCols() const { return fieldCount; } + uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; } + bool IsLoaded() const { return (data != NULL); } + char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable); + char* AutoProduceStringsArrayHolders(const char* fmt, char* dataTable); + char* AutoProduceStrings(const char* fmt, char* dataTable, LocaleConstant loc); + static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL); + static uint32 GetFormatStringsFields(const char * format); +private: + + uint32 recordSize; + uint32 recordCount; + uint32 fieldCount; + uint32 stringSize; + uint32 *fieldsOffset; + unsigned char *data; + unsigned char *stringTable; + + // WDB2 / WCH2 fields + uint32 tableHash; // WDB2 + uint32 build; // WDB2 + + int unk1; // WDB2 (Unix time in WCH2) + int unk2; // WDB2 + int unk3; // WDB2 (index table) + int locale; // WDB2 + int unk5; // WDB2 +}; + +#endif diff --git a/src/shared/Database/DB2Store.h b/src/shared/Database/DB2Store.h new file mode 100644 index 000000000..19c023591 --- /dev/null +++ b/src/shared/Database/DB2Store.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005-2012 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DB2STORE_H +#define DB2STORE_H + +#include "DB2FileLoader.h" + +template +class DB2Storage +{ + typedef std::list StringPoolList; +public: + explicit DB2Storage(const char *f) : nCount(0), fieldCount(0), fmt(f), indexTable(NULL), m_dataTable(NULL) { } + ~DB2Storage() { Clear(); } + + T const* LookupEntry(uint32 id) const { return (id>=nCount)?NULL:indexTable[id]; } + uint32 GetNumRows() const { return nCount; } + char const* GetFormat() const { return fmt; } + uint32 GetFieldCount() const { return fieldCount; } + + bool Load(char const* fn, LocaleConstant loc) + { + DB2FileLoader db2; + // Check if load was sucessful, only then continue + if(!db2.Load(fn, fmt)) + return false; + + fieldCount = db2.GetCols(); + + // load raw non-string data + m_dataTable = (T*)db2.AutoProduceData(fmt,nCount,(char**&)indexTable); + + // create string holders for loaded string fields + m_stringPoolList.push_back(db2.AutoProduceStringsArrayHolders(fmt,(char*)m_dataTable)); + + // load strings from dbc data + m_stringPoolList.push_back(db2.AutoProduceStrings(fmt,(char*)m_dataTable,loc)); + + // error in dbc file at loading if NULL + return indexTable!=NULL; + } + + bool LoadStringsFrom(char const* fn, LocaleConstant loc) + { + // DBC must be already loaded using Load + if(!indexTable) + return false; + + DB2FileLoader db2; + // Check if load was successful, only then continue + if(!db2.Load(fn, fmt)) + return false; + + // load strings from another locale dbc data + m_stringPoolList.push_back(db2.AutoProduceStrings(fmt,(char*)m_dataTable,loc)); + + return true; + } + + void Clear() + { + if (!indexTable) + return; + + delete[] ((char*)indexTable); + indexTable = NULL; + delete[] ((char*)m_dataTable); + m_dataTable = NULL; + + while(!m_stringPoolList.empty()) + { + delete[] m_stringPoolList.front(); + m_stringPoolList.pop_front(); + } + nCount = 0; + } + + void EraseEntry(uint32 id) { indexTable[id] = NULL; } + +private: + uint32 nCount; + uint32 fieldCount; + char const* fmt; + T** indexTable; + T* m_dataTable; + StringPoolList m_stringPoolList; +}; + +#endif diff --git a/src/shared/Database/DBCFileLoader.h b/src/shared/Database/DBCFileLoader.h index 89d14347b..e9fe5aebc 100644 --- a/src/shared/Database/DBCFileLoader.h +++ b/src/shared/Database/DBCFileLoader.h @@ -23,7 +23,7 @@ #include "Common.h" #include -enum +/*enum { FT_NA = 'x', // ignore/ default, 4 byte size, in Source String means field is ignored, in Dest String means field is filled with default value FT_NA_BYTE = 'X', // ignore/ default, 1 byte size, see above @@ -36,7 +36,7 @@ enum FT_SORT = 'd', // sorted by this field, field is not included FT_IND = 'n', // the same,but parsed to data FT_LOGIC = 'l' // Logical (boolean) -}; +};*/ class DBCFileLoader { diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj index 34b98a40c..ba31d1e46 100644 --- a/win/VC100/game.vcxproj +++ b/win/VC100/game.vcxproj @@ -388,6 +388,7 @@ + @@ -555,6 +556,9 @@ + + + diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters index 247339451..c609a05de 100644 --- a/win/VC100/game.vcxproj.filters +++ b/win/VC100/game.vcxproj.filters @@ -513,6 +513,8 @@ World/Handlers + + Server @@ -972,6 +974,14 @@ World/Handlers + + Server + + + Server + + + Server \ No newline at end of file diff --git a/win/VC100/shared.vcxproj b/win/VC100/shared.vcxproj index db11965a5..691fcd603 100644 --- a/win/VC100/shared.vcxproj +++ b/win/VC100/shared.vcxproj @@ -439,6 +439,7 @@ + @@ -461,6 +462,8 @@ + + diff --git a/win/VC100/shared.vcxproj.filters b/win/VC100/shared.vcxproj.filters index 33f871e25..6c1b48cfc 100644 --- a/win/VC100/shared.vcxproj.filters +++ b/win/VC100/shared.vcxproj.filters @@ -84,6 +84,9 @@ Database + + Database\DataStores + @@ -182,6 +185,12 @@ Database + + Database\DataStores + + + Database\DataStores +