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:
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "SpellInfo.h"
|
||||
#include "Path.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Timer.h"
|
||||
#include <list>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1332
-1313
File diff suppressed because it is too large
Load Diff
+1005
-1324
File diff suppressed because it is too large
Load Diff
Executable → Regular
+7
-6
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "SpellScript.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "DB2Stores.h"
|
||||
|
||||
extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
|
||||
|
||||
|
||||
@@ -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) );
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -307,7 +307,7 @@ public:
|
||||
uint32 opcode;
|
||||
parsedStream >> opcode;
|
||||
|
||||
WorldPacket data(opcode, 0);
|
||||
WorldPacket data(Opcodes(opcode), 0);
|
||||
|
||||
while (!parsedStream.eof())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user