Initial Commit for client version change to 4.2.2 (14545)

- added known opcodes (handlers are commented till not updated)
- added bitstream support to bytebuffer
- updated realm auth for 14545
- updated world auth
- fixed char_enum,create,delete handlers
- added DB2 reader
- added opcode logging to debuglogmask (ignores loglevel)
- fixed compile in win64, others not yet tested
- using db2 values for item models at char_enum to prevent client crash

Lots of Thanks to All SingularityCore Members
This commit is contained in:
Rat
2011-11-20 18:28:18 +01:00
parent 10b89d976f
commit d1affc4340
43 changed files with 4130 additions and 3045 deletions
@@ -65,7 +65,7 @@ enum LoginResult
LOGIN_LOCKED_ENFORCED = 0x10,
};
#define POST_BC_ACCEPTED_CLIENT_BUILD {12340, 11723, 11403, 11159, 10571, 10505, 10146, 9947, 8606, 0}
#define POST_BC_ACCEPTED_CLIENT_BUILD {14545 ,12340, 11723, 11403, 11159, 10571, 10505, 10146, 9947, 8606, 0}
#define PRE_BC_ACCEPTED_CLIENT_BUILD {5875, 6005, 0}
enum ExpansionFlags
@@ -25,6 +25,7 @@
#include "ConditionMgr.h"
#include "CreatureTextMgr.h"
#include "Spell.h"
#include "DB2Stores.h"
//#include "SmartScript.h"
//#include "SmartAI.h"
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "DB2Stores.h"
#include "Logging/Log.h"
#include "SharedDefines.h"
#include "SpellMgr.h"
#include "DB2fmt.h"
#include <map>
DB2Storage <ItemEntry> sItemStore(Itemfmt);
DB2Storage <ItemSparseEntry> sItemSparseStore (ItemSparsefmt);
DB2Storage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
typedef std::list<std::string> StoreProblemList1;
uint32 DB2FilesCount = 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<class T>
inline void LoadDB2(uint32& availableDb2Locales, StoreProblemList1& errlist, DB2Storage<T>& storage, const std::string& db2_path, const std::string& filename)
{
// compatibility format and C++ structure sizes
ASSERT(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDB2_assert_print(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename));
++DB2FilesCount;
std::string db2_filename = db2_path + filename;
if (storage.Load(db2_filename.c_str()))
{
}
else
{
// sort problematic db2 to (1) non compatible and (2) nonexistent
FILE * f = fopen(db2_filename.c_str(), "rb");
if (f)
{
char buf[100];
snprintf(buf, 100,"(exist, but have %d fields instead " SIZEFMTD ") Wrong client version DBC file?", storage.GetFieldCount(), strlen(storage.GetFormat()));
errlist.push_back(db2_filename + buf);
fclose(f);
}
else
errlist.push_back(db2_filename);
}
}
void LoadDB2Stores(const std::string& dataPath)
{
std::string db2Path = dataPath + "dbc/";
StoreProblemList1 bad_db2_files;
uint32 availableDb2Locales = 0xFFFFFFFF;
LoadDB2(availableDb2Locales, bad_db2_files, sItemStore, db2Path, "Item.db2");
LoadDB2(availableDb2Locales, bad_db2_files, sItemSparseStore, db2Path, "Item-sparse.db2");
LoadDB2(availableDb2Locales, bad_db2_files, sItemExtendedCostStore, db2Path, "ItemExtendedCost.db2");
// error checks
if (bad_db2_files.size() >= DB2FilesCount)
{
sLog->outError("\nIncorrect DataDir value in worldserver.conf or ALL required *.db2 files (%d) not found by path: %sdb2", DB2FilesCount, dataPath.c_str());
exit(1);
}
else if (!bad_db2_files.empty())
{
std::string str;
for (std::list<std::string>::iterator i = bad_db2_files.begin(); i != bad_db2_files.end(); ++i)
str += *i + "\n";
sLog->outError("\nSome required *.db2 files (%u from %d) not found or not compatible:\n%s", (uint32)bad_db2_files.size(), DB2FilesCount,str.c_str());
exit(1);
}
// Check loaded DB2 files proper version
if (!sItemStore.LookupEntry(72068) || // last item added in 4.2.2 (14545)
!sItemExtendedCostStore.LookupEntry(3652) ) // last item extended cost added in 4.2.2 (14545)
{
sLog->outString("");
sLog->outError("Please extract correct db2 files from client 4.2.2 14545.");
exit(1);
}
sLog->outString(">> Initialized %d DB2 data stores.", DB2FilesCount);
sLog->outString();
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_DB2STORES_H
#define TRINITY_DB2STORES_H
#include "Common.h"
#include "DB2Store.h"
#include "DB2Structure.h"
#include <list>
extern DB2Storage <ItemEntry> sItemStore;
extern DB2Storage <ItemSparseEntry> sItemSparseStore;
extern DB2Storage <ItemExtendedCostEntry> sItemExtendedCostStore;
void LoadDB2Stores(const std::string& dataPath);
#endif
+135
View File
@@ -0,0 +1,135 @@
/*
* Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_DB2STRUCTURE_H
#define TRINITY_DB2STRUCTURE_H
#include "Common.h"
#include "DBCEnums.h"
#include "Define.h"
#include "Path.h"
#include "Util.h"
#include "Vehicle.h"
#include "SharedDefines.h"
#include <map>
#include <set>
#include <vector>
// Structures used 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 ItemSparseEntry
{
uint32 ID; // 0
uint32 Quality; // 1
uint32 Flags; // 2
uint32 Flags2; // 3
uint32 BuyPrice; // 4
uint32 SellPrice; // 5
uint32 InventoryType; // 6
int32 AllowableClass; // 7
int32 AllowableRace; // 8
uint32 ItemLevel; // 9
int32 RequiredLevel; // 10
uint32 RequiredSkill; // 11
uint32 RequiredSkillRank; // 12
uint32 RequiredSpell; // 13
uint32 RequiredHonorRank; // 14
uint32 RequiredCityRank; // 15
uint32 RequiredReputationFaction; // 16
uint32 RequiredReputationRank; // 17
uint32 MaxCount; // 18
uint32 Stackable; // 19
uint32 ContainerSlots; // 20
int32 ItemStatType[MAX_ITEM_PROTO_STATS]; // 21 - 30
uint32 ItemStatValue[MAX_ITEM_PROTO_STATS]; // 31 - 40
int32 ItemStatUnk1[MAX_ITEM_PROTO_STATS]; // 41 - 50
int32 ItemStatUnk2[MAX_ITEM_PROTO_STATS]; // 51 - 60
uint32 ScalingStatDistribution; // 61
uint32 DamageType; // 62
uint32 Delay; // 63
float RangedModRange; // 64
int32 SpellId[MAX_ITEM_PROTO_SPELLS]; // 65 - 69
int32 SpellTrigger[MAX_ITEM_PROTO_SPELLS]; // 70 - 74
int32 SpellCharges[MAX_ITEM_PROTO_SPELLS]; // 75 - 79
int32 SpellCooldown[MAX_ITEM_PROTO_SPELLS]; // 80 - 84
int32 SpellCategory[MAX_ITEM_PROTO_SPELLS]; // 85 - 89
int32 SpellCategoryCooldown[MAX_ITEM_PROTO_SPELLS]; // 90 - 94
uint32 Bonding; // 95
DB2String Name; // 96
DB2String Name2; // 97
DB2String Name3; // 98
DB2String Name4; // 99
DB2String Description; // 100
uint32 PageText; // 101
uint32 LanguageID; // 102
uint32 PageMaterial; // 103
uint32 StartQuest; // 104
uint32 LockID; // 105
int32 Material; // 106
uint32 Sheath; // 107
uint32 RandomProperty; // 108
uint32 RandomSuffix; // 109
uint32 ItemSet; // 110
uint32 MaxDurability; // 111
uint32 Area; // 112
uint32 Map; // 113
uint32 BagFamily; // 114
uint32 TotemCategory; // 115
uint32 Color[MAX_ITEM_PROTO_SOCKETS]; // 116 - 118
uint32 Content[MAX_ITEM_PROTO_SOCKETS]; // 119 - 121
int32 SocketBonus; // 122
uint32 GemProperties; // 123
float ArmorDamageModifier; // 124
uint32 Duration; // 125
uint32 ItemLimitCategory; // 126
uint32 HolidayId; // 127
float StatScalingFactor; // 128
int32 Field130; // 129
int32 Field131; // 130
};
#define MAX_ITEM_EXT_COST_ITEMS 5
#define MAX_ITEM_EXT_COST_CURRENCIES 5
struct ItemExtendedCostEntry
{
uint32 ID; // 0 extended-cost entry id
//uint32 reqhonorpoints; // 1 required honor points
//uint32 reqarenapoints; // 2 required arena points
uint32 RequiredArenaSlot; // 3 arena slot restrictions (min slot value)
uint32 RequiredItem[MAX_ITEM_EXT_COST_ITEMS]; // 4-8 required item id
uint32 RequiredItemCount[MAX_ITEM_EXT_COST_ITEMS]; // 9-13 required count of 1st item
uint32 RequiredPersonalArenaRating; // 14 required personal arena rating
//uint32 ItemPurchaseGroup; // 15
uint32 RequiredCurrency[MAX_ITEM_EXT_COST_CURRENCIES];// 16-20 required curency id
uint32 RequiredCurrencyCount[MAX_ITEM_EXT_COST_CURRENCIES];// 21-25 required curency count
//uint32 Unknown[5]; // 26-30
};
#endif
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_DB2SFRM_H
#define TRINITY_DB2SFRM_H
const char Itemfmt[]="niiiiiii";
const char ItemSparsefmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisssssiiiiiiiiiiiiiiiiiiiiiiifiiifii";
const char ItemExtendedCostEntryfmt[]="nxxiiiiiiiiiiiixiiiiiiiiiixxxxx";
#endif
+9
View File
@@ -439,4 +439,13 @@ enum VehicleSeatFlagsB
VEHICLE_SEAT_FLAG_B_VEHICLE_PLAYERFRAME_UI = 0x80000000, // Lua_UnitHasVehiclePlayerFrameUI - actually checked for flagsb &~ 0x80000000
};
// CreatureType.dbc
enum CurrencyTypes
{
CURRENCY_TYPE_CONQUEST_POINTS = 390,
CURRENCY_TYPE_HONOR_POINTS = 392,
CURRENCY_TYPE_JUSTICE_POINTS = 395,
CURRENCY_TYPE_VALOR_POINTS = 396
};
#endif
+8 -8
View File
@@ -107,11 +107,11 @@ DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptf
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
DBCStorage <ItemEntry> sItemStore(Itemfmt);
//DBCStorage <ItemEntry> sItemStore(Itemfmt);
DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
//DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently
DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
//DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore(ItemLimitCategoryEntryfmt);
DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt);
DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);
@@ -344,11 +344,11 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sHolidaysStore, dbcPath, "Holidays.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemStore, dbcPath, "Item.dbc");
// LoadDBC(availableDbcLocales, bad_dbc_files, sItemStore, dbcPath, "Item.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemBagFamilyStore, dbcPath, "ItemBagFamily.dbc");
//LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemDisplayInfoStore, dbcPath, "ItemDisplayInfo.dbc"); -- not used currently
//LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemCondExtCostsStore, dbcPath, "ItemCondExtCosts.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemExtendedCostStore, dbcPath, "ItemExtendedCost.dbc");
// LoadDBC(availableDbcLocales, bad_dbc_files, sItemExtendedCostStore, dbcPath, "ItemExtendedCost.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemLimitCategoryStore, dbcPath, "ItemLimitCategory.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemRandomPropertiesStore, dbcPath, "ItemRandomProperties.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemRandomSuffixStore, dbcPath, "ItemRandomSuffix.dbc");
@@ -623,8 +623,8 @@ void LoadDBCStores(const std::string& dataPath)
if (!sAreaStore.LookupEntry(3617) || // last area (areaflag) added in 3.3.5a
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
!sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a
!sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a
//!sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a
//!sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a
!sMapStore.LookupEntry(724) || // last map added in 3.3.5a
!sSpellStore.LookupEntry(80864) ) // last client known item added in 3.3.5a
{
@@ -632,7 +632,7 @@ void LoadDBCStores(const std::string& dataPath)
exit(1);
}
sLog->outString(">> Initialized %d data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime));
sLog->outString(">> Initialized %d DBC data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime));
sLog->outString();
}
@@ -866,7 +866,7 @@ uint32 const* GetTalentTabPages(uint8 cls)
DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore() { return &sSoundEntriesStore; }
DBCStorage <SpellRangeEntry> const* GetSpellRangeStore() { return &sSpellRangeStore; }
DBCStorage <FactionEntry> const* GetFactionStore() { return &sFactionStore; }
DBCStorage <ItemEntry> const* GetItemDisplayStore() { return &sItemStore; }
// DBCStorage <ItemEntry> const* GetItemDisplayStore() { return &sItemStore; }
DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore() { return &sCreatureDisplayInfoStore; }
DBCStorage <EmotesEntry> const* GetEmotesStore() { return &sEmotesStore; }
DBCStorage <EmotesTextEntry> const* GetEmotesTextStore() { return &sEmotesTextStore; }
+3 -3
View File
@@ -109,10 +109,10 @@ extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore;
extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
extern DBCStorage <HolidaysEntry> sHolidaysStore;
extern DBCStorage <ItemEntry> sItemStore;
//extern DBCStorage <ItemEntry> sItemStore;
extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
//extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently
extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
//extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore;
extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore;
extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore;
@@ -176,7 +176,7 @@ void LoadDBCStores(const std::string& dataPath);
DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore();
DBCStorage <SpellRangeEntry> const* GetSpellRangeStore();
DBCStorage <FactionEntry> const* GetFactionStore();
DBCStorage <ItemEntry> const* GetItemDisplayStore();
// DBCStorage <ItemEntry> const* GetItemDisplayStore();
DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore();
DBCStorage <EmotesEntry> const* GetEmotesStore();
DBCStorage <EmotesTextEntry> const* GetEmotesTextStore();
+15 -8
View File
@@ -783,10 +783,17 @@ struct CurrencyCategoryEntry
struct CurrencyTypesEntry
{
//uint32 ID; // 0 not used
uint32 ItemId; // 1 used as real index
//uint32 Category; // 2 may be category
uint32 BitIndex; // 3 bit index in PLAYER_FIELD_KNOWN_CURRENCIES (1 << (index-1))
uint32 ID; // 0 not used
//uint32 Category; // 1 may be category
//DBCString name; // 2
//DBCString iconName; // 3
//uint32 unk4; // 4 all 0
//uint32 unk5; // 5 archaeology-related (?)
//uint32 unk6; // 6 archaeology-related (?)
uint32 TotalCap; // 7
uint32 WeekCap; // 8
//int32 unk9; // 9
//DBCString description; // 10
};
struct DestructibleModelDataEntry
@@ -1060,7 +1067,7 @@ struct HolidaysEntry
//uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1)
};
struct ItemEntry
/*struct ItemEntry
{
uint32 ID; // 0
uint32 Class; // 1
@@ -1070,7 +1077,7 @@ struct ItemEntry
uint32 DisplayId; // 5
uint32 InventoryType; // 6
uint32 Sheath; // 7
};
};*/
struct ItemBagFamilyEntry
{
@@ -1105,7 +1112,7 @@ struct ItemDisplayInfoEntry
#define MAX_ITEM_EXTENDED_COST_REQUIREMENTS 5
struct ItemExtendedCostEntry
/*struct ItemExtendedCostEntry
{
uint32 ID; // 0 extended-cost entry id
uint32 reqhonorpoints; // 1 required honor points
@@ -1114,7 +1121,7 @@ struct ItemExtendedCostEntry
uint32 reqitem[MAX_ITEM_EXTENDED_COST_REQUIREMENTS]; // 4-8 required item id
uint32 reqitemcount[MAX_ITEM_EXTENDED_COST_REQUIREMENTS]; // 9-14 required count of 1st item
uint32 reqpersonalarenarating; // 15 required personal arena rating};
};
};*/
struct ItemLimitCategoryEntry
{
+1 -1
View File
@@ -42,7 +42,7 @@ const char CreatureDisplayInfofmt[]="nxxxfxxxxxxxxxxx";
const char CreatureFamilyfmt[]="nfifiiiiixssssssssssssssssxx";
const char CreatureSpellDatafmt[]="niiiixxxx";
const char CreatureTypefmt[]="nxxxxxxxxxxxxxxxxxx";
const char CurrencyTypesfmt[]="xnxi";
const char CurrencyTypesfmt[]="nxxxxxxiixx";//14545
const char DestructibleModelDatafmt[]="nxxixxxixxxixxxixxx";
const char DungeonEncounterfmt[]="niixissssssssssssssssxx";
const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
+307 -137
View File
@@ -74,6 +74,7 @@
#include "InstanceScript.h"
#include <cmath>
#include "AccountMgr.h"
#include "DB2Stores.h"
#define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
@@ -1851,8 +1852,7 @@ void Player::setDeathState(DeathState s)
//clear aura case after resurrection by another way (spells will be applied before next death)
SetUInt32Value(PLAYER_SELF_RES_SPELL, 0);
}
bool Player::BuildEnumData(QueryResult result, WorldPacket* data)
bool Player::BuildEnumData(QueryResult result, ByteBuffer* data)
{
// 0 1 2 3 4 5 6 7
// "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
@@ -1861,63 +1861,87 @@ bool Player::BuildEnumData(QueryResult result, WorldPacket* data)
// 15 16 17 18 19 20 21
// "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_banned.guid, character_declinedname.genitive "
Field* fields = result->Fetch();
Field *fields = result->Fetch();
//uint64 GuildGuid = (*result)[13].GetUInt32();//TODO: store as uin64
uint32 guid = fields[0].GetUInt32();
uint8 plrRace = fields[2].GetUInt8();
uint8 plrClass = fields[3].GetUInt8();
uint8 gender = fields[4].GetUInt8();
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(plrRace, plrClass);
if (!info)
{
sLog->outError("Player %u has incorrect race/class pair. Don't build enum.", guid);
return false;
}
else if (!IsValidGender(gender))
{
sLog->outError("Player (%u) has incorrect gender (%hu), don't build enum.", guid, gender);
return false;
}
*data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
*data << fields[1].GetString(); // name
*data << uint8(plrRace); // race
*data << uint8(plrClass); // class
*data << uint8(gender); // gender
uint8 level = fields[7].GetUInt8();
uint32 GuidLow = fields[0].GetUInt32();
uint32 playerBytes = fields[5].GetUInt32();
*data << uint8(playerBytes); // skin
*data << uint8(playerBytes >> 8); // face
*data << uint8(playerBytes >> 16); // hair style
*data << uint8(playerBytes >> 24); // hair color
uint32 playerBytes2 = fields[6].GetUInt32();
*data << uint8(playerBytes2 & 0xFF); // facial hair
*data << uint8(fields[7].GetUInt8()); // level
*data << uint32(fields[8].GetUInt32()); // zone
*data << uint32(fields[9].GetUInt32()); // map
*data << fields[10].GetFloat(); // x
*data << fields[11].GetFloat(); // y
*data << fields[12].GetFloat(); // z
*data << uint32(fields[13].GetUInt32()); // guild id
uint32 charFlags = 0;
uint32 playerFlags = fields[14].GetUInt32();
uint32 atLoginFlags = fields[15].GetUInt32();
uint32 zone = fields[8].GetUInt32();
uint32 petDisplayId = 0;
uint32 petLevel = 0;
uint32 petFamily = 0;
// show pet at selection character in character list only for non-ghost character
if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (plrClass == CLASS_WARLOCK || plrClass == CLASS_HUNTER || plrClass == CLASS_DEATH_KNIGHT))
{
uint32 entry = fields[16].GetUInt32();
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry);
if (creatureInfo)
{
petDisplayId = fields[17].GetUInt32();
petLevel = fields[18].GetUInt16();
petFamily = creatureInfo->family;
}
}
*data << fields[1].GetString(); // name
*data << uint8(playerBytes >> 8); // face
*data << uint32(fields[9].GetUInt32()); // map
uint8 Guid0 = uint8(GuidLow);
uint8 Guid1 = uint8(GuidLow >> 8);
uint8 Guid2 = uint8(GuidLow >> 16);
uint8 Guid3 = uint8(GuidLow >> 24);
if (Guid1)
*data << uint8(Guid1^1);
//if (uint8(GuildGuid))
// *data << uint8(GuildGuid^1);
*data << fields[10].GetFloat(); // x
*data << fields[11].GetFloat(); // y
*data << fields[12].GetFloat(); // z
if (Guid0)
*data << uint8(Guid0^1);
*data << uint32(zone); // Zone id
*data << uint32(petLevel); // pet level
if (Guid3)
*data << uint8(Guid3^1);
//*data << uint8(2); // unk, bit 14
uint32 playerBytes2 = fields[6].GetUInt32();
*data << uint8(playerBytes2 & 0xFF); // facial hair
*data << uint8(playerBytes); // skin
*data << uint8(plrClass); // class
*data << uint32(petFamily); // Pet Family
uint32 charFlags = 0;
if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
charFlags |= CHARACTER_FLAG_HIDE_HELM;
if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
charFlags |= CHARACTER_FLAG_HIDE_CLOAK;
if (playerFlags & PLAYER_FLAGS_GHOST)
charFlags |= CHARACTER_FLAG_GHOST;
if (atLoginFlags & AT_LOGIN_RENAME)
charFlags |= CHARACTER_FLAG_RENAME;
if (fields[20].GetUInt32())
charFlags |= CHARACTER_FLAG_LOCKED_BY_BILLING;
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
{
if (!fields[21].GetString().empty())
@@ -1926,60 +1950,52 @@ bool Player::BuildEnumData(QueryResult result, WorldPacket* data)
else
charFlags |= CHARACTER_FLAG_DECLINED;
*data << uint32(charFlags); // character flags
*data << uint32(charFlags); // character flags
// character customize flags
if (atLoginFlags & AT_LOGIN_CUSTOMIZE)
*data << uint32(CHAR_CUSTOMIZE_FLAG_CUSTOMIZE);
else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION)
*data << uint32(CHAR_CUSTOMIZE_FLAG_FACTION);
else if (atLoginFlags & AT_LOGIN_CHANGE_RACE)
*data << uint32(CHAR_CUSTOMIZE_FLAG_RACE);
else
*data << uint32(CHAR_CUSTOMIZE_FLAG_NONE);
if (Guid2)
*data << uint8(Guid2^1);
// First login
*data << uint8(atLoginFlags & AT_LOGIN_FIRST ? 1 : 0);
*data << uint32(petDisplayId); // Pet DisplayID
//if (uint8(GuildGuid >> 56))
// *data << uint8(GuildGuid^1 >> 56);
*data << uint8(level); // Level
*data << uint8(playerBytes >> 16); // Hair style
//if (uint8(GuildGuid >> 16))
// *data << uint8(GuildGuid^1 >> 16);
*data << uint8(plrRace); // Race
*data << uint8(playerBytes >> 24); // Hair color
// Pets info
uint32 petDisplayId = 0;
uint32 petLevel = 0;
uint32 petFamily = 0;
// show pet at selection character in character list only for non-ghost character
if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (plrClass == CLASS_WARLOCK || plrClass == CLASS_HUNTER || plrClass == CLASS_DEATH_KNIGHT))
{
uint32 entry = fields[16].GetUInt32();
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry);
if (creatureInfo)
{
petDisplayId = fields[17].GetUInt32();
petLevel = fields[18].GetUInt16();
petFamily = creatureInfo->family;
}
}
*data << uint32(petDisplayId);
*data << uint32(petLevel);
*data << uint32(petFamily);
//if (uint8(GuildGuid >> 48))
// *data << uint8(GuildGuid^1 >> 48);
*data << uint8(gender); // Gender
//if (uint8(GuildGuid >> 24))
// *data << uint8(GuildGuid^1 >> 24);
*data << uint8(0); // character order id (used for char list positioning) TODO: implement
Tokens equipment(fields[19].GetString(), ' ');
for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot)
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot)
{
uint32 visualBase = slot * 2;
uint32 itemId = GetUInt32ValueFromArray(equipment, visualBase);
uint32 visualbase = slot * 2;
uint32 itemId = GetUInt32ValueFromArray(equipment, visualbase);
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
ItemEntry const *db2Item = sItemStore.LookupEntry(itemId); // Use Item.db2.DisplayID for Char Enum
if (!proto || !db2Item)
{
*data << uint32(0);
*data << uint8(0);
*data << uint32(0);
continue;
}
SpellItemEnchantmentEntry const* enchant = NULL;
uint32 enchants = GetUInt32ValueFromArray(equipment, visualBase + 1);
SpellItemEnchantmentEntry const *enchant = NULL;
uint32 enchants = GetUInt32ValueFromArray(equipment, visualbase + 1);
for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
{
// values stored in 2 uint16
@@ -1991,12 +2007,36 @@ bool Player::BuildEnumData(QueryResult result, WorldPacket* data)
if (enchant)
break;
}
*data << uint32(proto->DisplayInfoID);
*data << uint8(proto->InventoryType);
sLog->outError("entry %u aura %u invtype %u display %u", itemId, enchant ? enchant->aura_id : uint32(0), proto->InventoryType,db2Item->DisplayId);
*data << uint32(enchant ? enchant->aura_id : 0);
*data << uint8(proto->InventoryType);
*data << uint32(db2Item->DisplayId);
}
// Bags (not supported) TODO: implement
for (uint32 i = 0; i < 4; ++i)
{
*data << uint32(0); // enchant
*data << uint8(0); // invtype
*data << uint32(0); // displayid
}
// character customize flags
if (atLoginFlags & AT_LOGIN_CUSTOMIZE)
*data << uint32(CHAR_CUSTOMIZE_FLAG_CUSTOMIZE);
else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION)
*data << uint32(CHAR_CUSTOMIZE_FLAG_FACTION);
else if (atLoginFlags & AT_LOGIN_CHANGE_RACE)
*data << uint32(CHAR_CUSTOMIZE_FLAG_RACE);
else
*data << uint32(CHAR_CUSTOMIZE_FLAG_NONE);
//if (uint8(GuildGuid >> 8))
// *data << uint8(GuildGuid^1 >> 8);
return true;
}
@@ -7244,6 +7284,154 @@ bool Player::RewardHonor(Unit* uVictim, uint32 groupsize, int32 honor, bool pvpt
return true;
}
void Player::SendCurrencies() const
{
WorldPacket packet(SMSG_INIT_CURRENCY, 4 + m_currencies.size()*(5*4 + 1));
packet << uint32(m_currencies.size());
for (PlayerCurrenciesMap::const_iterator itr = m_currencies.begin(); itr != m_currencies.end(); ++itr)
{
const CurrencyTypesEntry* entry = sCurrencyTypesStore.LookupEntry(itr->first);
packet << uint32(itr->second.weekCount / PLAYER_CURRENCY_PRECISION);
packet << uint8(0); // unknown
packet << uint32(entry->ID);
packet << uint32(sWorld->GetNextWeeklyQuestsResetTime() - 1*WEEK);
packet << uint32(_GetCurrencyWeekCap(entry) / PLAYER_CURRENCY_PRECISION);
packet << uint32(itr->second.totalCount / PLAYER_CURRENCY_PRECISION);
}
GetSession()->SendPacket(&packet);
}
uint32 Player::GetCurrency(uint32 id) const
{
PlayerCurrenciesMap::const_iterator itr = m_currencies.find(id);
return itr != m_currencies.end() ? itr->second.totalCount : 0;
}
bool Player::HasCurrency(uint32 id, uint32 count) const
{
PlayerCurrenciesMap::const_iterator itr = m_currencies.find(id);
return itr != m_currencies.end() && itr->second.totalCount >= count;
}
void Player::ModifyCurrency(uint32 id, int32 count)
{
if (!count)
return;
const CurrencyTypesEntry* currency = sCurrencyTypesStore.LookupEntry(id);
ASSERT(currency);
uint32 oldTotalCount = 0;
uint32 oldWeekCount = 0;
PlayerCurrenciesMap::iterator itr = m_currencies.find(id);
if (itr == m_currencies.end())
{
PlayerCurrency cur;
cur.state = PLAYERCURRENCY_NEW;
cur.totalCount = 0;
cur.weekCount = 0;
m_currencies[id] = cur;
itr = m_currencies.find(id);
}
else
{
oldTotalCount = itr->second.totalCount;
oldWeekCount = itr->second.weekCount;
}
int32 newTotalCount = int32(oldTotalCount) + count;
if (newTotalCount < 0)
newTotalCount = 0;
int32 newWeekCount = int32(oldWeekCount) + (count > 0 ? count : 0);
if (newWeekCount < 0)
newWeekCount = 0;
if (currency->TotalCap && int32(currency->TotalCap) < newTotalCount)
{
int32 delta = newTotalCount - int32(currency->TotalCap);
newTotalCount = int32(currency->TotalCap);
newWeekCount -= delta;
}
// TODO: fix conquest points
uint32 weekCap = _GetCurrencyWeekCap(currency);
if (weekCap && int32(weekCap) < newTotalCount)
{
int32 delta = newWeekCount - int32(weekCap);
newWeekCount = int32(weekCap);
newTotalCount -= delta;
}
// if we change total, we must change week
ASSERT(((newTotalCount-oldTotalCount) != 0) == ((newWeekCount-oldWeekCount) != 0));
if (newTotalCount != oldTotalCount)
{
if(itr->second.state != PLAYERCURRENCY_NEW)
itr->second.state = PLAYERCURRENCY_CHANGED;
itr->second.totalCount = newTotalCount;
itr->second.weekCount = newWeekCount;
// probably excessive checks
if (IsInWorld() && !GetSession()->PlayerLoading())
{
WorldPacket packet(SMSG_UPDATE_CURRENCY, 12);
packet << uint32(id);
packet << uint32(weekCap ? (newWeekCount / PLAYER_CURRENCY_PRECISION) : 0);
packet << uint32(newTotalCount / PLAYER_CURRENCY_PRECISION);
GetSession()->SendPacket(&packet);
}
}
}
void Player::SetCurrency(uint32 id, uint32 count)
{
ModifyCurrency(id, int32(count) - GetCurrency(id));
}
uint32 Player::_GetCurrencyWeekCap(const CurrencyTypesEntry* currency) const
{
uint32 cap = currency->WeekCap;
switch (currency->ID)
{
case CURRENCY_TYPE_CONQUEST_POINTS:
{
// TODO: implement
cap = 0;
break;
}
case CURRENCY_TYPE_HONOR_POINTS:
{
uint32 honorcap = sWorld->getIntConfig(CONFIG_MAX_HONOR_POINTS);
if (honorcap > 0)
cap = honorcap;
break;
}
case CURRENCY_TYPE_JUSTICE_POINTS:
{
uint32 justicecap = sWorld->getIntConfig(CONFIG_MAX_JUSTICE_POINTS);
if (justicecap > 0)
cap = justicecap;
break;
}
}
if (cap != currency->WeekCap && IsInWorld() && !GetSession()->PlayerLoading())
{
WorldPacket packet(SMSG_UPDATE_CURRENCY_WEEK_LIMIT, 8);
packet << uint32(cap / PLAYER_CURRENCY_PRECISION);
packet << uint32(currency->ID);
GetSession()->SendPacket(&packet);
}
return cap;
}
void Player::SetHonorPoints(uint32 value)
{
if (value > sWorld->getIntConfig(CONFIG_MAX_HONOR_POINTS))
@@ -19698,7 +19886,7 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
val += (*itr)->value;
}
val += apply ? mod->value : -(mod->value);
WorldPacket data(Opcode, (1+1+4));
WorldPacket data(Opcodes(Opcode), (1+1+4));
data << uint8(eff);
data << uint8(mod->op);
data << int32(val);
@@ -20324,7 +20512,7 @@ void Player::InitDisplayIds()
}
}
inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore)
inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const *pProto, Creature *pVendor, VendorItem const* crItem, bool bStore)
{
ItemPosCountVec vDest;
uint16 uiDest = 0;
@@ -20339,19 +20527,19 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c
ModifyMoney(-price);
if (crItem->ExtendedCost) // case for new honor system
if (crItem->ExtendedCost) // case for new honor system
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if (iece->reqhonorpoints)
ModifyHonorPoints(- int32(iece->reqhonorpoints * count));
if (iece->reqarenapoints)
ModifyArenaPoints(- int32(iece->reqarenapoints * count));
for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i)
for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
{
if (iece->reqitem[i])
DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true);
if (iece->RequiredItem[i])
DestroyItemCount(iece->RequiredItem[i], iece->RequiredItem[i], true);
}
for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
{
if (iece->RequiredCurrency[i])
ModifyCurrency(iece->RequiredCurrency[i], -int32(iece->RequiredCurrencyCount[i]));
}
}
@@ -20460,24 +20648,10 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
return false;
}
// honor points price
if (GetHonorPoints() < (iece->reqhonorpoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL);
return false;
}
// arena points price
if (GetArenaPoints() < (iece->reqarenapoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL);
return false;
}
// item base price
for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i)
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
{
if (iece->reqitem[i] && !HasItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count)))
if (iece->RequiredItem[i] && !HasItemCount(iece->RequiredItem[i], (iece->RequiredItemCount[i] * count)))
{
SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL);
return false;
@@ -20485,7 +20659,7 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
}
// check for personal arena rating requirement
if (GetMaxPersonalArenaRatingRequirement(iece->reqarenaslot) < iece->reqpersonalarenarating)
if (GetMaxPersonalArenaRatingRequirement(iece->RequiredArenaSlot) < iece->RequiredPersonalArenaRating)
{
// probably not the proper equip err
SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, NULL, NULL);
@@ -23755,7 +23929,7 @@ void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank)
void Player::AddKnownCurrency(uint32 itemId)
{
if (CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId))
SetFlag64(PLAYER_FIELD_KNOWN_CURRENCIES, (1LL << (ctEntry->BitIndex-1)));
SetFlag64(0, (1LL << (ctEntry->ID-1)));
}
void Player::UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcode)
@@ -24491,7 +24665,7 @@ void Player::DeleteRefundReference(uint32 it)
}
}
void Player::SendRefundInfo(Item* item)
void Player::SendRefundInfo(Item *item)
{
// This function call unsets ITEM_FLAGS_REFUNDABLE if played time is over 2 hours.
item->UpdatePlayedTime(this);
@@ -24518,13 +24692,11 @@ void Player::SendRefundInfo(Item* item)
WorldPacket data(SMSG_ITEM_REFUND_INFO_RESPONSE, 8+4+4+4+4*4+4*4+4+4);
data << uint64(item->GetGUID()); // item guid
data << uint32(item->GetPaidMoney()); // money cost
data << uint32(iece->reqhonorpoints); // honor point cost
data << uint32(iece->reqarenapoints); // arena point cost
for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) // item cost data
data << uint32(item->GetPaidMoney()); // money cost
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) // item cost data
{
data << uint32(iece->reqitem[i]);
data << uint32(iece->reqitemcount[i]);
data << uint32(iece->RequiredItem[i]);
data << uint32(iece->RequiredItemCount[i]);
}
data << uint32(0);
data << uint32(GetTotalPlayedTime() - item->GetPlayedTime());
@@ -24589,8 +24761,8 @@ void Player::RefundItem(Item* item)
bool store_error = false;
for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i)
{
uint32 count = iece->reqitemcount[i];
uint32 itemid = iece->reqitem[i];
uint32 count = iece->RequiredItemCount[i];
uint32 itemid = iece->RequiredItem[i];
if (count && itemid)
{
@@ -24617,12 +24789,10 @@ void Player::RefundItem(Item* item)
data << uint64(item->GetGUID()); // item guid
data << uint32(0); // 0, or error code
data << uint32(item->GetPaidMoney()); // money cost
data << uint32(iece->reqhonorpoints); // honor point cost
data << uint32(iece->reqarenapoints); // arena point cost
for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) // item cost data
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) // item cost data
{
data << uint32(iece->reqitem[i]);
data << uint32(iece->reqitemcount[i]);
data << uint32(iece->RequiredItem[i]);
data << uint32(iece->RequiredItemCount[i]);
}
GetSession()->SendPacket(&data);
@@ -24638,10 +24808,10 @@ void Player::RefundItem(Item* item)
DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
// Grant back extendedcost items
for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i)
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
{
uint32 count = iece->reqitemcount[i];
uint32 itemid = iece->reqitem[i];
uint32 count = iece->RequiredItemCount[i];
uint32 itemid = iece->RequiredItem[i];
if (count && itemid)
{
ItemPosCountVec dest;
@@ -24657,12 +24827,12 @@ void Player::RefundItem(Item* item)
ModifyMoney(moneyRefund); // Saved in SaveInventoryAndGoldToDB
// Grant back Honor points
if (uint32 honorRefund = iece->reqhonorpoints)
ModifyHonorPoints(honorRefund, &trans);
//if (uint32 honorRefund = iece->reqhonorpoints)
// ModifyHonorPoints(honorRefund, &trans);
// Grant back Arena points
if (uint32 arenaRefund = iece->reqarenapoints)
ModifyArenaPoints(arenaRefund, &trans);
//if (uint32 arenaRefund = iece->reqarenapoints)
// ModifyArenaPoints(arenaRefund, &trans);
SaveInventoryAndGoldToDB(trans);
+27 -1
View File
@@ -124,9 +124,26 @@ struct SpellModifier
Aura* const ownerAura;
};
enum PlayerCurrencyState
{
PLAYERCURRENCY_UNCHANGED = 0,
PLAYERCURRENCY_CHANGED = 1,
PLAYERCURRENCY_NEW = 2,
PLAYERCURRENCY_REMOVED = 3
};
struct PlayerCurrency
{
PlayerCurrencyState state;
uint32 totalCount;
uint32 weekCount;
};
typedef UNORDERED_MAP<uint32, PlayerTalent*> PlayerTalentMap;
typedef UNORDERED_MAP<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::list<SpellModifier*> SpellModList;
typedef UNORDERED_MAP<uint32, PlayerCurrency> PlayerCurrenciesMap;
#define PLAYER_CURRENCY_PRECISION 100
typedef std::list<uint64> WhisperListContainer;
@@ -1114,7 +1131,7 @@ class Player : public Unit, public GridObject<Player>
void Update(uint32 time);
static bool BuildEnumData(QueryResult result, WorldPacket* data);
static bool BuildEnumData(QueryResult result, ByteBuffer* data);
void SetInWater(bool apply);
@@ -1296,6 +1313,12 @@ class Player : public Unit, public GridObject<Player>
void AddRefundReference(uint32 it);
void DeleteRefundReference(uint32 it);
void SendCurrencies() const;
uint32 GetCurrency(uint32 id) const;
bool HasCurrency(uint32 id, uint32 count) const;
void SetCurrency(uint32 id, uint32 count);
void ModifyCurrency(uint32 id, int32 count);
void ApplyEquipCooldown(Item* pItem);
void SetAmmo(uint32 item);
void RemoveAmmo();
@@ -2613,6 +2636,9 @@ class Player : public Unit, public GridObject<Player>
Item* m_items[PLAYER_SLOTS_COUNT];
uint32 m_currentBuybackSlot;
PlayerCurrenciesMap m_currencies;
uint32 _GetCurrencyWeekCap(const CurrencyTypesEntry* currency) const;
std::vector<Item*> m_itemUpdateQueue;
bool m_itemUpdateQueueBlocked;
+1
View File
@@ -35,6 +35,7 @@
#include "SpellInfo.h"
#include "Path.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Timer.h"
#include <list>
+4 -2
View File
@@ -45,6 +45,8 @@
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "PoolMgr.h"
#include "DB2Structure.h"
#include "DB2Stores.h"
ScriptMapMap sQuestEndScripts;
ScriptMapMap sQuestStartScripts;
@@ -2253,7 +2255,7 @@ void ObjectMgr::LoadItemTemplates()
// Checks
ItemEntry const* dbcitem = sItemStore.LookupEntry(entry);
/*ItemEntry const* dbcitem = sItemStore.LookupEntry(entry);
if (dbcitem)
{
@@ -2297,7 +2299,7 @@ void ObjectMgr::LoadItemTemplates()
}
else
sLog->outErrorDb("Item (Entry: %u) does not exist in item.dbc! (not correct id?).", entry);
sLog->outErrorDb("Item (Entry: %u) does not exist in item.dbc! (not correct id?).", entry);*/
if (itemTemplate.Class >= MAX_ITEM_CLASS)
{
@@ -198,29 +198,100 @@ bool LoginQueryHolder::Initialize()
void WorldSession::HandleCharEnum(QueryResult result)
{
WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size
WorldPacket data(SMSG_CHAR_ENUM, 270);
uint8 num = 0;
data << uint8(0x80); // 0 causes the client to free memory of charlist
data << uint32(0); // number of characters
data << uint32(0); // unk loop counter
data << num;
_allowedCharsToLogin.clear();
if (result)
{
typedef std::pair<uint32, uint64> Guids;
std::vector<Guids> guidsVect;
ByteBuffer buffer;
_allowedCharsToLogin.clear();
do
{
uint32 guidlow = (*result)[0].GetUInt32();
sLog->outDetail("Loading char guid %u from account %u.", guidlow, GetAccountId());
if (Player::BuildEnumData(result, &data))
uint32 GuidLow = (*result)[0].GetUInt32();
uint64 GuildGuid = (*result)[13].GetUInt32();//TODO: store as uin64
guidsVect.push_back(std::make_pair(GuidLow, GuildGuid));
sLog->outDetail("Loading char guid %u from account %u.", GuidLow, GetAccountId());
if (!Player::BuildEnumData(result, &buffer))
{
_allowedCharsToLogin.insert(guidlow);
++num;
sLog->outError("Building enum data for SMSG_CHAR_ENUM has failed, aborting");
return;
}
_allowedCharsToLogin.insert(GuidLow);
}
while (result->NextRow());
}
data.put<uint8>(0, num);
for (std::vector<Guids>::iterator itr = guidsVect.begin(); itr != guidsVect.end(); ++itr)
{
uint32 GuidLow = (*itr).first;
uint64 GuildGuid = (*itr).second;
uint8 Guid0 = uint8(GuidLow);
uint8 Guid1 = uint8(GuidLow >> 8);
uint8 Guid2 = uint8(GuidLow >> 16);
uint8 Guid3 = uint8(GuidLow >> 24);
for (uint8 i = 0; i < 17; ++i)
{
switch(i)
{
//case 14:
// data.writeBit(1);//unk
// break;
case 11: data.writeBit(Guid0 ? 1 : 0); break;
case 12: data.writeBit(Guid1 ? 1 : 0); break;
case 9: data.writeBit(Guid2 ? 1 : 0); break;
case 8: data.writeBit(Guid3 ? 1 : 0); break;
/*case 15:
if(uint8(GuildGuid))
data.writeBit(1);
break;
case 4:
if(uint8(GuildGuid >> 8))
data.writeBit(1);
break;
case 13:
if(uint8(GuildGuid >> 16))
data.writeBit(1);
break;
case 2:
if(uint8(GuildGuid >> 24))
data.writeBit(1);
break;*/
/*case 0:
if(uint8(GuildGuid >> 32))
data.writeBit(1);
break;
case 0:
if(uint8(GuildGuid >> 40))
data.writeBit(1);
break;*/
/*case 5:
if(uint8(GuildGuid >> 48))
data.writeBit(1);
break;
case 3:
if(uint8(GuildGuid >> 56))
data.writeBit(1);
break;*/
default:
data.writeBit(0);
break;
}
}
}
data.flushBits();
data.append(buffer);
data.put<uint32>(1, guidsVect.size());
}
SendPacket(&data);
}
@@ -31,6 +31,8 @@
#include "Util.h"
#include "SpellAuras.h"
#include "Vehicle.h"
#include "DB2Structure.h"
#include "DB2Stores.h"
class Aura;
@@ -1227,7 +1227,7 @@ void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
return;
}
WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4);
WorldPacket data(SMSG_INSPECT_HONOR_STATS, 8+1+4*4);
data << uint64(player->GetGUID());
data << uint8(player->GetHonorPoints());
data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS));
@@ -340,7 +340,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data)
/*----------------------*/
/* process position-change */
WorldPacket data(opcode, recv_data.size());
WorldPacket data(Opcodes(opcode), recv_data.size());
movementInfo.time = getMSTime();
movementInfo.guid = mover->GetGUID();
WriteMovementInfo(&data, &movementInfo);
@@ -387,7 +387,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data)
void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data)
{
uint32 opcode = recv_data.GetOpcode();
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode);
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(Opcodes(opcode)), opcode, opcode);
/* extract packet */
uint64 guid;
@@ -423,15 +423,15 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data)
switch (opcode)
{
case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break;
case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break;
case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break;
case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break;
case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break;
case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break;
case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break;
case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break;
case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break;
//case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break;
//case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break;
//case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break;
//case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break;
//case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break;
//case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break;
//case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break;
//case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break;
//case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break;
default:
sLog->outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode);
return;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -20,33 +20,34 @@
#define TRINITYCORE_WORLDPACKET_H
#include "Common.h"
#include "Opcodes.h"
#include "ByteBuffer.h"
class WorldPacket : public ByteBuffer
{
public:
// just container for later use
WorldPacket() : ByteBuffer(0), m_opcode(0)
WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE)
{
}
explicit WorldPacket(uint16 opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { }
explicit WorldPacket(Opcodes opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { }
// copy constructor
WorldPacket(const WorldPacket &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode)
{
}
void Initialize(uint16 opcode, size_t newres=200)
void Initialize(Opcodes opcode, size_t newres=200)
{
clear();
_storage.reserve(newres);
m_opcode = opcode;
}
uint16 GetOpcode() const { return m_opcode; }
void SetOpcode(uint16 opcode) { m_opcode = opcode; }
Opcodes GetOpcode() const { return m_opcode; }
void SetOpcode(Opcodes opcode) { m_opcode = opcode; }
protected:
uint16 m_opcode;
Opcodes m_opcode;
};
#endif
+102 -91
View File
@@ -43,16 +43,26 @@
#include "ScriptMgr.h"
#include "Transport.h"
Opcodes PacketFilter::DropHighBytes(Opcodes opcode)
{
if (opcode & 0xFFFF0000) // check if any High byte is present
return Opcodes(opcode >> 16);
else
return Opcodes(opcode);
}
bool MapSessionFilter::Process(WorldPacket* packet)
{
OpcodeHandler const &opHandle = opcodeTable[packet->GetOpcode()];
Opcodes opcode = DropHighBytes(packet->GetOpcode());
const OpcodeHandler* opHandle = opcodeTable[opcode];
//let's check if our opcode can be really processed in Map::Update()
if (opHandle.packetProcessing == PROCESS_INPLACE)
if (opHandle->packetProcessing == PROCESS_INPLACE)
return true;
//we do not process thread-unsafe packets
if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
if (opHandle->packetProcessing == PROCESS_THREADUNSAFE)
return false;
Player* player = m_pSession->GetPlayer();
@@ -67,13 +77,14 @@ bool MapSessionFilter::Process(WorldPacket* packet)
//OR packet handler is not thread-safe!
bool WorldSessionFilter::Process(WorldPacket* packet)
{
OpcodeHandler const &opHandle = opcodeTable[packet->GetOpcode()];
Opcodes opcode = DropHighBytes(packet->GetOpcode());
const OpcodeHandler* opHandle = opcodeTable[opcode];
//check if packet handler is supposed to be safe
if (opHandle.packetProcessing == PROCESS_INPLACE)
if (opHandle->packetProcessing == PROCESS_INPLACE)
return true;
//thread-unsafe packets should be processed in World::UpdateSessions()
if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
if (opHandle->packetProcessing == PROCESS_THREADUNSAFE)
return true;
//no player attached? -> our client! ^^
@@ -148,6 +159,14 @@ void WorldSession::SendPacket(WorldPacket const* packet)
if (!m_Socket)
return;
if (packet->GetOpcode() == UNKNOWN_OPCODE)
{
sLog->outError("Sending unknown opcode - prevented. Trace:");
ACE_Stack_Trace trace;
sLog->outError("%s", trace.c_str());
return;
}
#ifdef TRINITY_DEBUG
// Code for network use statistic
static uint64 sendPacketCount = 0;
@@ -224,99 +243,91 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
WorldPacket* packet = NULL;
while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet, updater))
{
if (packet->GetOpcode() >= NUM_MSG_TYPES)
const OpcodeHandler* opHandle = opcodeTable[packet->GetOpcode()];
try
{
sLog->outError("SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
sScriptMgr->OnUnknownPacketReceive(m_Socket, WorldPacket(*packet));
}
else
{
OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()];
try
switch (opHandle->status)
{
switch (opHandle.status)
{
case STATUS_LOGGEDIN:
if (!_player)
{
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
if (!m_playerRecentlyLogout)
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN", "the player has not logged in yet");
}
else if (_player->IsInWorld())
{
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
(this->*opHandle.handler)(*packet);
if (sLog->IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break;
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
if (!_player && !m_playerRecentlyLogout)
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
"the player has not logged in yet and not recently logout");
else
{
// not expected _player or must checked in packet hanlder
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
(this->*opHandle.handler)(*packet);
if (sLog->IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
break;
case STATUS_TRANSFER:
if (!_player)
LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet");
else if (_player->IsInWorld())
LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world");
else
{
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
(this->*opHandle.handler)(*packet);
if (sLog->IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
break;
case STATUS_AUTHED:
// prevent cheating with skip queue wait
if (m_inQueue)
{
LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet");
break;
}
// single from authed time opcodes send in to after logout time
// and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes.
if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL)
m_playerRecentlyLogout = false;
case STATUS_LOGGEDIN:
if (!_player)
{
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
if (!m_playerRecentlyLogout)
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN", "the player has not logged in yet");
}
else if (_player->IsInWorld())
{
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
(this->*opHandle.handler)(*packet);
(this->*opHandle->handler)(*packet);
if (sLog->IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break;
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
if (!_player && !m_playerRecentlyLogout)
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
"the player has not logged in yet and not recently logout");
else
{
// not expected _player or must checked in packet hanlder
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
(this->*opHandle->handler)(*packet);
if (sLog->IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
break;
case STATUS_TRANSFER:
if (!_player)
LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet");
else if (_player->IsInWorld())
LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world");
else
{
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
(this->*opHandle->handler)(*packet);
if (sLog->IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
break;
case STATUS_AUTHED:
// prevent cheating with skip queue wait
if (m_inQueue)
{
LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet");
break;
case STATUS_NEVER:
sLog->outError("SESSION (account: %u, guidlow: %u, char: %s): received not allowed opcode %s (0x%.4X)",
GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>",
LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
break;
case STATUS_UNHANDLED:
sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION (account: %u, guidlow: %u, char: %s): received not handled opcode %s (0x%.4X)",
GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>",
LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
break;
}
}
// single from authed time opcodes send in to after logout time
// and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes.
if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL)
m_playerRecentlyLogout = false;
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
(this->*opHandle->handler)(*packet);
if (sLog->IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
break;
case STATUS_NEVER:
sLog->outError("SESSION (account: %u, guidlow: %u, char: %s): received not allowed opcode %s (0x%.4X)",
GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>",
LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
break;
case STATUS_UNHANDLED:
sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION (account: %u, guidlow: %u, char: %s): received not handled opcode %s (0x%.4X)",
GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>",
LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
break;
}
catch(ByteBufferException &)
}
catch(ByteBufferException &)
{
sLog->outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.",
packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
if (sLog->IsOutDebug())
{
sLog->outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.",
packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
if (sLog->IsOutDebug())
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "Dumping error causing packet:");
packet->hexlike();
}
sLog->outDebug(LOG_FILTER_NETWORKIO, "Dumping error causing packet:");
packet->hexlike();
}
}
+1
View File
@@ -147,6 +147,7 @@ public:
virtual bool Process(WorldPacket* /*packet*/) { return true; }
virtual bool ProcessLogout() const { return true; }
static Opcodes DropHighBytes(Opcodes opcode);
protected:
WorldSession* const m_pSession;
+127 -106
View File
@@ -179,6 +179,8 @@ int WorldSocket::SendPacket (const WorldPacket& pct)
sWorldLog->outLog("\n");
}
sLog->outOpCode(uint32(pct.GetOpcode()), LookupOpcodeName(pct.GetOpcode()), true);
// Create a copy of the original packet; this is to avoid issues if a hook modifies it.
sScriptMgr->OnPacketSend(this, WorldPacket(pct));
@@ -257,19 +259,9 @@ int WorldSocket::open (void *a)
}
m_Address = remote_addr.get_host_addr();
// Send startup packet.
WorldPacket packet (SMSG_AUTH_CHALLENGE, 24);
packet << uint32(1); // 1...31
packet << m_Seed;
BigNumber seed1;
seed1.SetRand(16 * 8);
packet.append(seed1.AsByteArray(16), 16); // new encryption seeds
BigNumber seed2;
seed2.SetRand(16 * 8);
packet.append(seed2.AsByteArray(16), 16); // new encryption seeds
WorldPacket packet(SMSG_VERIFY_CONNECTIVITY);
packet << "RLD OF WARCRAFT CONNECTION - SERVER TO CLIENT";
if (SendPacket(packet) == -1)
return -1;
@@ -493,7 +485,7 @@ int WorldSocket::handle_input_header (void)
EndianConvertReverse(header.size);
EndianConvert(header.cmd);
if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240))
if ((header.size < 4) || (header.size > 10240))
{
Player* _player = m_Session ? m_Session->GetPlayer() : NULL;
sLog->outError ("WorldSocket::handle_input_header(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %d, cmd: %d)",
@@ -508,7 +500,7 @@ int WorldSocket::handle_input_header (void)
header.size -= 4;
ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1);
ACE_NEW_RETURN (m_RecvWPct, WorldPacket (PacketFilter::DropHighBytes(Opcodes(header.cmd)), header.size), -1);
if (header.size > 0)
{
@@ -681,7 +673,7 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
// manage memory ;)
ACE_Auto_Ptr<WorldPacket> aptr (new_pct);
const ACE_UINT16 opcode = new_pct->GetOpcode();
const ACE_UINT16 opcode = PacketFilter::DropHighBytes(new_pct->GetOpcode());
if (closing_)
return -1;
@@ -706,6 +698,8 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
sWorldLog->outLog ("\n");
}
sLog->outOpCode(uint32(Opcodes(opcode)), LookupOpcodeName(Opcodes(opcode)), false);
try
{
switch (opcode)
@@ -725,10 +719,23 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
sLog->outStaticDebug ("CMSG_KEEP_ALIVE, size: " UI64FMTD, uint64(new_pct->size()));
sScriptMgr->OnPacketReceive(this, WorldPacket(*new_pct));
return 0;
case CMSG_LOG_DISCONNECT:
sLog->outStaticDebug("CMSG_LOG_DISCONNECT , size: " UI64FMTD, uint64(new_pct->size()));
sScriptMgr->OnPacketReceive(this, WorldPacket(*new_pct));
return 0;
case CMSG_VERIFY_CONNECTIVITY_RESPONSE:
sLog->outStaticDebug("CMSG_VERIFY_CONNECTIVITY_RESPONSE , size: " UI64FMTD, uint64(new_pct->size()));
sScriptMgr->OnPacketReceive(this, WorldPacket(*new_pct));
return HandleSendAuthSession();
default:
{
ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
if (!opcodeTable[Opcodes(opcode)])
{
sLog->outError("Opcode with no defined handler received from client: %u", new_pct->GetOpcode());
return 0;
}
if (m_Session != NULL)
{
// Our Idle timer will reset on any non PING opcodes.
@@ -766,23 +773,66 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
ACE_NOTREACHED (return 0);
}
int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
int WorldSocket::HandleSendAuthSession()
{
// NOTE: ATM the socket is singlethread, have this in mind ...
uint8 digest[20];
uint32 clientSeed;
uint32 unk2, unk3, unk5, unk6, unk7;
uint64 unk4;
uint32 BuiltNumberClient;
uint32 id, security;
//uint8 expansion = 0;
LocaleConstant locale;
std::string account;
SHA1Hash sha1;
BigNumber v, s, g, N;
WorldPacket packet, SendAddonPacked;
WorldPacket packet(SMSG_AUTH_CHALLENGE, 37);
packet << uint32(0);
packet << uint32(0);
packet << uint32(0);
packet << uint32(0);
packet << m_Seed;
packet << uint8(1);
packet << uint32(0);
packet << uint32(0);
packet << uint32(0);
packet << uint32(0);
return SendPacket(packet);
}
BigNumber K;
int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
{
uint8 digest[20];
uint16 clientBuild, security;
uint32 id;
uint32 m_addonSize;
uint32 clientSeed;
std::string account;
LocaleConstant locale;
SHA1Hash sha1;
BigNumber v, s, g, N, K;
WorldPacket packet;
recvPacket.read_skip<uint8>();
recvPacket.read(digest, 5);
recvPacket >> clientBuild;
recvPacket.read(digest, 2);
recvPacket.read_skip<uint8>();
recvPacket.read_skip<uint32>();
recvPacket.read(digest, 4);
recvPacket.read_skip<uint64>();
recvPacket.read_skip<uint8>();
recvPacket.read(digest, 2);
recvPacket.read_skip<uint32>();
recvPacket.read(digest, 4);
recvPacket >> clientSeed;
recvPacket.read(digest, 2);
recvPacket.read_skip<uint32>();
recvPacket.read(digest, 1);
recvPacket.read_skip<uint32>();
recvPacket >> account;
recvPacket >> m_addonSize;
uint8 * tableauAddon = new uint8[m_addonSize];
WorldPacket packetAddon;
for (uint32 i = 0; i < m_addonSize; i++)
{
uint8 ByteSize = 0;
recvPacket >> ByteSize;
tableauAddon[i] = ByteSize;
packetAddon << ByteSize;
}
delete tableauAddon;
if (sWorld->IsClosed())
{
@@ -790,47 +840,30 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
packet << uint8(AUTH_REJECT);
SendPacket (packet);
sLog->outError ("WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteAddress().c_str());
sLog->outError("WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteAddress().c_str());
return -1;
}
// Read the content of the packet
recvPacket >> BuiltNumberClient; // for now no use
recvPacket >> unk2;
recvPacket >> account;
recvPacket >> unk3;
recvPacket >> clientSeed;
recvPacket >> unk5 >> unk6 >> unk7;
recvPacket >> unk4;
recvPacket.read(digest, 20);
sLog->outStaticDebug ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u",
BuiltNumberClient,
unk2,
account.c_str(),
unk3,
clientSeed);
// Get the account information from the realmd database
std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
LoginDatabase.EscapeString (safe_account);
// No SQL injection, username escaped.
QueryResult result =
LoginDatabase.PQuery ("SELECT "
"id, " //0
"sessionkey, " //1
"last_ip, " //2
"locked, " //3
"v, " //4
"s, " //5
"expansion, " //6
"mutetime, " //7
"locale, " //8
"recruiter " //9
"FROM account "
"WHERE username = '%s'",
safe_account.c_str());
LoginDatabase.PQuery ("SELECT "
"id, " //0
"sessionkey, " //1
"last_ip, " //2
"locked, " //3
"v, " //4
"s, " //5
"expansion, " //6
"mutetime, " //7
"locale, " //8
"recruiter " //9
"FROM account "
"WHERE username = '%s'",
safe_account.c_str());
// Stop if the account is not found
if (!result)
@@ -860,9 +893,9 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
const char* sStr = s.AsHexStr(); //Must be freed by OPENSSL_free()
const char* vStr = v.AsHexStr(); //Must be freed by OPENSSL_free()
sLog->outStaticDebug ("WorldSocket::HandleAuthSession: (s, v) check s: %s v: %s",
sStr,
vStr);
sLog->outStaticDebug ("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s",
sStr,
vStr);
OPENSSL_free ((void*) sStr);
OPENSSL_free ((void*) vStr);
@@ -882,15 +915,14 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
}
id = fields[0].GetUInt32();
/*
if (security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB
security = SEC_ADMINISTRATOR;
*/
K.SetHexStr (fields[1].GetCString());
int64 mutetime = fields[7].GetInt64();
//! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
if (mutetime < 0)
{
mutetime = time(NULL) + llabs(mutetime);
LoginDatabase.PExecute("UPDATE account SET mutetime = " SI64FMTD " WHERE id = '%u'", mutetime, id);
}
time_t mutetime = time_t (fields[7].GetUInt64());
locale = LocaleConstant (fields[8].GetUInt8());
if (locale >= TOTAL_LOCALES)
@@ -899,15 +931,14 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
uint32 recruiter = fields[9].GetUInt32();
// Checks gmlevel per Realm
result =
LoginDatabase.PQuery ("SELECT "
"RealmID, " //0
"gmlevel " //1
"FROM account_access "
"WHERE id = '%d'"
" AND (RealmID = '%d'"
" OR RealmID = '-1')",
id, realmID);
result = LoginDatabase.PQuery ("SELECT "
"RealmID, " //0
"gmlevel " //1
"FROM account_access "
"WHERE id = '%d'"
" AND (RealmID = '%d'"
" OR RealmID = '-1')",
id, realmID);
if (!result)
security = 0;
else
@@ -918,10 +949,10 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Re-check account ban (same check as in realmd)
QueryResult banresult =
LoginDatabase.PQuery ("SELECT 1 FROM account_banned WHERE id = %u AND active = 1 "
"UNION "
"SELECT 1 FROM ip_banned WHERE ip = '%s'",
id, GetRemoteAddress().c_str());
LoginDatabase.PQuery ("SELECT 1 FROM account_banned WHERE id = %u AND active = 1 "
"UNION "
"SELECT 1 FROM ip_banned WHERE ip = '%s'",
id, GetRemoteAddress().c_str());
if (banresult) // if account banned
{
@@ -936,7 +967,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Check locked state for server
AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
sLog->outDebug(LOG_FILTER_NETWORKIO, "Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security));
if (AccountTypes(security) < allowedAccountType)
if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
{
WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
Packet << uint8 (AUTH_UNAVAILABLE);
@@ -960,22 +991,11 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
sha.UpdateBigNumbers (&K, NULL);
sha.Finalize();
if (memcmp (sha.GetDigest(), digest, 20))
{
packet.Initialize (SMSG_AUTH_RESPONSE, 1);
packet << uint8 (AUTH_FAILED);
SendPacket (packet);
sLog->outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
return -1;
}
std::string address = GetRemoteAddress();
sLog->outStaticDebug ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
account.c_str(),
address.c_str());
account.c_str(),
address.c_str());
// Check if this user is by any chance a recruiter
result = LoginDatabase.PQuery ("SELECT 1 FROM account WHERE recruiter = %u", id);
@@ -989,10 +1009,10 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
LoginDatabase.EscapeString (address);
LoginDatabase.PExecute ("UPDATE account "
"SET last_ip = '%s' "
"WHERE username = '%s'",
address.c_str(),
safe_account.c_str());
"SET last_ip = '%s' "
"WHERE username = '%s'",
address.c_str(),
safe_account.c_str());
// NOTE ATM the socket is single-threaded, have this in mind ...
ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1);
@@ -1001,7 +1021,8 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
m_Session->LoadGlobalAccountData();
m_Session->LoadTutorialsData();
m_Session->ReadAddonsInfo(recvPacket);
packetAddon.rpos(0);
m_Session->ReadAddonsInfo(packetAddon);
// Sleep this Network thread for
uint32 sleepTime = sWorld->getIntConfig(CONFIG_SESSION_ADD_DELAY);
+3
View File
@@ -161,6 +161,9 @@ class WorldSocket : public WorldHandler
/// Called by ProcessIncoming() on CMSG_PING.
int HandlePing (WorldPacket& recvPacket);
/// Called by CMSG_VERIFY_CONNECTIVITY_RESPONSE
int HandleSendAuthSession();
private:
/// Time in which the last ping was received
ACE_Time_Value m_LastPingTime;
+1
View File
@@ -53,6 +53,7 @@
#include "SpellScript.h"
#include "InstanceScript.h"
#include "SpellInfo.h"
#include "DB2Stores.h"
extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
+5
View File
@@ -45,6 +45,7 @@
#include "GroupMgr.h"
#include "Chat.h"
#include "DBCStores.h"
#include "DB2Stores.h"
#include "LootMgr.h"
#include "ItemEnchantmentMgr.h"
#include "MapManager.h"
@@ -1257,6 +1258,7 @@ void World::SetInitialWorldSettings()
///- Load the DBC files
sLog->outString("Initialize data stores...");
LoadDBCStores(m_dataPath);
LoadDB2Stores(m_dataPath);
DetectDBCLang();
sLog->outString("Loading spell dbc data corrections...");
@@ -1739,6 +1741,9 @@ void World::SetInitialWorldSettings()
else
sLog->SetLogDB(false);
sLog->outString("Initializing Opcodes...");
InitOpcodes();
uint32 startupDuration = GetMSTimeDiffToNow(startupBegin);
sLog->outString();
sLog->outString("WORLD: World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000) );
+4 -2
View File
@@ -213,8 +213,10 @@ enum WorldIntConfigs
CONFIG_START_PLAYER_MONEY,
CONFIG_MAX_HONOR_POINTS,
CONFIG_START_HONOR_POINTS,
CONFIG_MAX_ARENA_POINTS,
CONFIG_START_ARENA_POINTS,
CONFIG_MAX_JUSTICE_POINTS,
CONFIG_START_JUSTICE_POINTS,
CONFIG_MAX_ARENA_POINTS,//todo: remove
CONFIG_START_ARENA_POINTS,//todo: remove
CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL,
CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE,
CONFIG_INSTANCE_RESET_TIME_HOUR,
+1 -1
View File
@@ -307,7 +307,7 @@ public:
uint32 opcode;
parsedStream >> opcode;
WorldPacket data(opcode, 0);
WorldPacket data(Opcodes(opcode), 0);
while (!parsedStream.eof())
{
+1 -1
View File
@@ -95,7 +95,7 @@ public:
if (!target)
target = handler->GetSession()->GetPlayer();
WorldPacket data(12);
WorldPacket data;
if (strncmp(args, "on", 3) == 0)
data.SetOpcode(SMSG_MOVE_SET_CAN_FLY);
else if (strncmp(args, "off", 4) == 0)
@@ -236,7 +236,7 @@ class instance_deadmines : public InstanceMapScript
void DoPlaySound(GameObject* unit, uint32 sound)
{
WorldPacket data(4);
WorldPacket data;
data.SetOpcode(SMSG_PLAY_SOUND);
data << uint32(sound);
unit->SendMessageToSet(&data, false);
@@ -244,7 +244,7 @@ class instance_deadmines : public InstanceMapScript
void DoPlaySoundCreature(Unit* unit, uint32 sound)
{
WorldPacket data(4);
WorldPacket data;
data.SetOpcode(SMSG_PLAY_SOUND);
data << uint32(sound);
unit->SendMessageToSet(&data, false);
@@ -241,8 +241,7 @@ public:
// Also needs an exception in spell system.
unit->CastSpell(unit, SPELL_GRAVITY_LAPSE_FLY, true, 0, 0, me->GetGUID());
// Use packet hack
WorldPacket data(12);
data.SetOpcode(SMSG_MOVE_SET_CAN_FLY);
WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12);
data.append(unit->GetPackGUID());
data << uint32(0);
unit->SendMessageToSet(&data, true);
@@ -261,8 +260,7 @@ public:
unit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY);
unit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT);
WorldPacket data(12);
data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY);
WorldPacket data(SMSG_MOVE_UNSET_CAN_FLY, 12);
data.append(unit->GetPackGUID());
data << uint32(0);
unit->SendMessageToSet(&data, true);
@@ -922,8 +922,7 @@ class boss_kaelthas : public CreatureScript
unit->CastSpell(unit, SPELL_GRAVITY_LAPSE_AURA, true, 0, 0, me->GetGUID());
//Using packet workaround
WorldPacket data(12);
data.SetOpcode(SMSG_MOVE_SET_CAN_FLY);
WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12);
data.append(unit->GetPackGUID());
data << uint32(0);
unit->SendMessageToSet(&data, true);
@@ -949,8 +948,7 @@ class boss_kaelthas : public CreatureScript
if (Unit* unit = Unit::GetUnit((*me), (*i)->getUnitGuid()))
{
//Using packet workaround
WorldPacket data(12);
data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY);
WorldPacket data(SMSG_MOVE_UNSET_CAN_FLY, 12);
data.append(unit->GetPackGUID());
data << uint32(0);
unit->SendMessageToSet(&data, true);
@@ -0,0 +1,411 @@
/*
* Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "Common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 (build > 12880)
{
if (fread(&unk2, 4, 1, f) != 1) // Unknown WDB2
{
fclose(f);
return false;
}
EndianConvert(unk2);
if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
{
fclose(f);
return false;
}
EndianConvert(maxIndex);
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);
}
if (maxIndex != 0)
{
int32 diff = maxIndex - unk2 + 1;
fseek(f, diff * 4 + diff * 2, SEEK_CUR); // diff * 4: an index for rows, diff * 2: a memory allocation bank
}
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')
fieldsOffset[i] += 1;
else
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:
case FT_INT:
recordsize += 4;
break;
case FT_STRING:
recordsize += sizeof(char*);
break;
case FT_SORT:
i = x;
break;
case FT_IND:
i = x;
recordsize += 4;
break;
case FT_BYTE:
recordsize += 1;
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)
{
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; y < recordCount; y++)
{
uint32 ind=getRecord(y).getUInt(i);
if (ind>maxi)
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 += 4;
break;
case FT_IND:
case FT_INT:
*((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
offset += 4;
break;
case FT_BYTE:
*((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
offset += 1;
break;
case FT_STRING:
*((char**)(&dataTable[offset])) = NULL; // will be replaces non-empty or "" strings in AutoProduceStrings
offset += sizeof(char*);
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*) * TOTAL_LOCALES;
size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize;
size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount;
char* stringHoldersPool = new char[stringHoldersPoolSize];
// DB2 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 < recordCount; y++)
{
uint32 stringFieldNum = 0;
for(uint32 x = 0; x < fieldCount; x++)
switch(format[x])
{
case FT_FLOAT:
case FT_IND:
case FT_INT:
offset += 4;
break;
case FT_BYTE:
offset += 1;
break;
case FT_STRING:
{
// init db2 string field slots by pointers to string holders
char const*** slot = (char const***)(&dataTable[offset]);
*slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringHolderSize*stringFieldNum]);
++stringFieldNum;
offset += sizeof(char*);
break;
}
case FT_NA:
case FT_NA_BYTE:
case FT_SORT:
break;
default:
assert(false && "unknown format character");
}
}
//send as char* for store in char* pool list for free at unload
return stringHoldersPool;
}
char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable)
{
if (strlen(format) != fieldCount)
return NULL;
// each string field at load have array of string for each locale
size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES;
char* stringPool= new char[stringSize];
memcpy(stringPool, stringTable, stringSize);
uint32 offset = 0;
for (uint32 y =0; y < recordCount; y++)
{
for (uint32 x = 0; x < fieldCount; x++)
switch(format[x])
{
case FT_FLOAT:
case FT_IND:
case FT_INT:
offset += 4;
break;
case FT_BYTE:
offset += 1;
break;
case FT_STRING:
{
// fill only not filled entries
char** slot = (char**)(&dataTable[offset]);
if (**((char***)slot) == nullStr)
{
const char * st = getRecord(y).getString(x);
*slot=stringPool + (st-(const char*)stringTable);
}
offset+=sizeof(char*);
break;
}
}
}
return stringPool;
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef DB2_FILE_LOADER_H
#define DB2_FILE_LOADER_H
#include "Define.h"
#include "Utilities/ByteConverter.h"
#include <cassert>
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<float*>(offset+file.GetOffset(field));
EndianConvert(val);
return val;
}
uint32 getUInt(size_t field) const
{
assert(field < file.fieldCount);
uint32 val = *reinterpret_cast<uint32*>(offset+file.GetOffset(field));
EndianConvert(val);
return val;
}
uint8 getUInt8(size_t field) const
{
assert(field < file.fieldCount);
return *reinterpret_cast<uint8*>(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<char*>(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);
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 maxIndex; // WDB2 (index table)
int locale; // WDB2
int unk5; // WDB2
};
#endif
+141
View File
@@ -0,0 +1,141 @@
/*
* Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef DB2STORE_H
#define DB2STORE_H
#include "DB2FileLoader.h"
#include "DB2fmt.h"
#include "Logging/Log.h"
#include "Field.h"
#include "DatabaseWorkerPool.h"
#include "Implementation/WorldDatabase.h"
#include "DatabaseEnv.h"
#include <vector>
template<class T>
class DB2Storage
{
typedef std::list<char*> StringPoolList;
typedef std::vector<T*> DataTableEx;
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; }
/// Copies the provided entry and stores it.
void AddEntry(uint32 id, const T* entry)
{
if (LookupEntry(id))
return;
if (id >= nCount)
{
// reallocate index table
char** tmpIdxTable = new char*[id+1];
memset(tmpIdxTable, 0, (id+1) * sizeof(char*));
memcpy(tmpIdxTable, (char*)indexTable, nCount * sizeof(char*));
delete[] ((char*)indexTable);
nCount = id + 1;
indexTable = (T**)tmpIdxTable;
}
T* entryDst = new T;
memcpy((char*)entryDst, (char*)entry, sizeof(T));
m_dataTableEx.push_back(entryDst);
indexTable[id] = entryDst;
}
bool Load(char const* fn)
{
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));
// error in dbc file at loading if NULL
return indexTable!=NULL;
}
bool LoadStringsFrom(char const* fn)
{
// 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));
return true;
}
void Clear()
{
if (!indexTable)
return;
delete[] ((char*)indexTable);
indexTable = NULL;
delete[] ((char*)m_dataTable);
m_dataTable = NULL;
for (DataTableEx::const_iterator itr = m_dataTableEx.begin(); itr != m_dataTableEx.end(); ++itr)
delete *itr;
m_dataTableEx.clear();
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;
uint32 recordSize;
char const* fmt;
T** indexTable;
T* m_dataTable;
DataTableEx m_dataTableEx;
StringPoolList m_stringPoolList;
};
#endif
+2 -2
View File
@@ -22,7 +22,7 @@
#include "Utilities/ByteConverter.h"
#include <cassert>
enum
/*enum
{
FT_NA='x', //not used or unknown, 4 byte size
FT_NA_BYTE='X', //not used or unknown, byte
@@ -35,7 +35,7 @@ enum
FT_LOGIC='l', //Logical (boolean)
FT_SQL_PRESENT='p', //Used in sql format to mark column present in sql dbc
FT_SQL_ABSENT='a' //Used in sql format to mark column absent in sql dbc
};
};*/
class DBCFileLoader
{
+17
View File
@@ -79,4 +79,21 @@ typedef ACE_UINT32 uint32;
typedef ACE_UINT16 uint16;
typedef ACE_UINT8 uint8;
typedef char const* const* DBCString; //char* DBCStrings[MAX_LOCALE];
typedef char const* const* DB2String; //char* DB2Strings[MAX_LOCALE];
enum
{
FT_NA='x', //not used or unknown, 4 byte size
FT_NA_BYTE='X', //not used or unknown, byte
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)
FT_SQL_PRESENT='p', //Used in sql format to mark column present in sql dbc
FT_SQL_ABSENT='a' //Used in sql format to mark column absent in sql dbc
};
#endif //TRINITY_DEFINE_H
+7
View File
@@ -986,6 +986,13 @@ void Log::outCharDump(const char * str, uint32 account_id, uint32 guid, const ch
}
}
void Log::outOpCode(uint32 op, const char * name, bool smsg)
{
if (!(m_DebugLogMask & LOG_FILTER_OPCODES))
return;
outString("%s: %s 0x%.4X (%u)", smsg ? "S->C" : "C->S", name, op, op);
}
void Log::outRemote(const char * str, ...)
{
if (!str)
+2
View File
@@ -50,6 +50,7 @@ enum DebugLogFilters
LOG_FILTER_LOOT = 0x00100000, // Loot related
LOG_FILTER_GUILD = 0x00200000, // Guild related
LOG_FILTER_TRANSPORTS = 0x00400000, // Transport related
LOG_FILTER_OPCODES = 0x00800000, // OpCodes
};
enum LogTypes
@@ -137,6 +138,7 @@ class Log
void outArena( const char * str, ... ) ATTR_PRINTF(2, 3);
void outSQLDriver( const char* str, ... ) ATTR_PRINTF(2, 3);
void outCharDump( const char * str, uint32 account_id, uint32 guid, const char * name );
void outOpCode(uint32 op, const char * name, bool smsg = true);
static void outTimestamp(FILE* file);
static std::string GetTimestampStr();
+63 -4
View File
@@ -51,19 +51,19 @@ class ByteBuffer
const static size_t DEFAULT_SIZE = 0x1000;
// constructor
ByteBuffer(): _rpos(0), _wpos(0)
ByteBuffer(): _rpos(0), _wpos(0), _bitpos(8), _curbitval(0)
{
_storage.reserve(DEFAULT_SIZE);
}
// constructor
ByteBuffer(size_t res): _rpos(0), _wpos(0)
ByteBuffer(size_t res): _rpos(0), _wpos(0), _bitpos(8), _curbitval(0)
{
_storage.reserve(res);
}
// copy constructor
ByteBuffer(const ByteBuffer &buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage) { }
ByteBuffer(const ByteBuffer &buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage), _bitpos(buf._bitpos), _curbitval(buf._curbitval) { }
void clear()
{
@@ -73,10 +73,68 @@ class ByteBuffer
template <typename T> void append(T value)
{
flushBits();
EndianConvert(value);
append((uint8 *)&value, sizeof(value));
}
void flushBits()
{
if (_bitpos == 8)
return;
append((uint8 *)&_curbitval, sizeof(uint8));
_curbitval = 0;
_bitpos = 8;
}
bool writeBit(uint32 bit)
{
--_bitpos;
if (bit)
_curbitval |= (1 << (_bitpos));
if (_bitpos == 0)
{
_bitpos = 8;
append((uint8 *)&_curbitval, sizeof(_curbitval));
_curbitval = 0;
}
return (bit != 0);
}
bool readBit()
{
++_bitpos;
if (_bitpos > 7)
{
_bitpos = 0;
_curbitval = read<uint8>();
}
bool bit = ((_curbitval >> (7-_bitpos)) & 1) != 0;
return bit;
}
template <typename T> void writeBits(T value, size_t bits)
{
for (int32 i = bits-1; i >= 0; --i)
writeBit((value >> i) & 1);
}
uint32 readBits(size_t bits)
{
uint32 value = 0;
for (int32 i = bits-1; i >= 0; --i)
{
if(readBit())
{
value |= (1 << (_bitpos));
}
}
return value;
}
template <typename T> void put(size_t pos, T value)
{
EndianConvert(value);
@@ -489,7 +547,8 @@ class ByteBuffer
}
protected:
size_t _rpos, _wpos;
size_t _rpos, _wpos, _bitpos;
uint8 _curbitval;
std::vector<uint8> _storage;
};
@@ -472,6 +472,7 @@ LogFileLevel = 0
# 1048576 - Anything related to loot
# 2097152 - Anything related to guilds
# 4194304 - Anything related to transports
# 8388608 - Incoming/outgoing Opcodes
#
# Simply add the values together to create a bitmask.
# For more info see enum DebugLogFilters in Log.h