aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Object/Object.cpp20
-rw-r--r--src/server/game/Entities/Player/Player.cpp17
-rw-r--r--src/server/game/Entities/Player/Player.h7
-rw-r--r--src/server/game/Handlers/AuthHandler.cpp26
-rw-r--r--src/server/game/Handlers/BattleGroundHandler.cpp10
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp399
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h89
-rw-r--r--src/server/game/Server/Packets/AuthenticationPackets.h2
-rw-r--r--src/server/game/Server/Packets/CharacterPackets.cpp96
-rw-r--r--src/server/game/Server/Packets/CharacterPackets.h177
-rw-r--r--src/server/game/Server/Packets/SystemPackets.cpp43
-rw-r--r--src/server/game/Server/Packets/SystemPackets.h53
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp17
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h52
-rw-r--r--src/server/game/Server/WorldPacket.h2
-rw-r--r--src/server/game/Server/WorldSession.cpp42
-rw-r--r--src/server/game/Server/WorldSession.h114
-rw-r--r--src/server/game/Tools/PlayerDump.cpp2
-rw-r--r--src/server/game/World/World.cpp17
-rw-r--r--src/server/game/World/World.h7
-rw-r--r--src/server/scripts/Commands/cs_character.cpp4
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp13
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h2
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp3
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h3
-rw-r--r--src/server/shared/Threading/Callback.h4
-rw-r--r--src/server/shared/Utilities/Util.h8
-rw-r--r--src/server/worldserver/worldserver.conf.dist23
28 files changed, 956 insertions, 296 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index ac3625ca3f4..8572d23bf64 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -359,17 +359,17 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const
bool EnablePortals = false;
bool PlayHoverAnim = false;
bool IsSuppressingGreetings = false;
- bool HasMovementUpdate = flags & UPDATEFLAG_LIVING ? true : false;
- bool HasMovementTransport = flags & UPDATEFLAG_TRANSPORT_POSITION ? true : false;
- bool Stationary = flags & UPDATEFLAG_STATIONARY_POSITION ? true : false;
- bool CombatVictim = flags & UPDATEFLAG_HAS_TARGET ? true : false;
- bool ServerTime = flags & UPDATEFLAG_TRANSPORT ? true : false;
- bool VehicleCreate = flags & UPDATEFLAG_VEHICLE ? true : false;
- bool AnimKitCreate = flags & UPDATEFLAG_ANIMKITS ? true : false;
- bool Rotation = flags & UPDATEFLAG_ROTATION ? true : false;
+ bool HasMovementUpdate = (flags & UPDATEFLAG_LIVING) != 0;
+ bool HasMovementTransport = (flags & UPDATEFLAG_TRANSPORT_POSITION) != 0;
+ bool Stationary = (flags & UPDATEFLAG_STATIONARY_POSITION) != 0;
+ bool CombatVictim = (flags & UPDATEFLAG_HAS_TARGET) != 0;
+ bool ServerTime = (flags & UPDATEFLAG_TRANSPORT) != 0;
+ bool VehicleCreate = (flags & UPDATEFLAG_VEHICLE) != 0;
+ bool AnimKitCreate = (flags & UPDATEFLAG_ANIMKITS) != 0;
+ bool Rotation = (flags & UPDATEFLAG_ROTATION) != 0;
bool HasAreaTrigger = false;
bool HasGameObject = false;
- bool ThisIsYou = flags & UPDATEFLAG_SELF ? true : false;
+ bool ThisIsYou = (flags & UPDATEFLAG_SELF) != 0;
bool ReplaceActive = false;
bool SceneObjCreate = false;
bool ScenePendingInstances = false;
@@ -379,7 +379,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const
PauseTimesCount = go->GetGOValue()->Transport.StopFrames->size();
data->WriteBit(NoBirthAnim);
- data->WriteBit(EnablePortals);
+ data->WriteBit(EnablePortals);
data->WriteBit(PlayHoverAnim);
data->WriteBit(IsSuppressingGreetings);
data->WriteBit(HasMovementUpdate);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index e45f7c896b9..be2563ea0ee 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -31,6 +31,7 @@
#include "Channel.h"
#include "ChannelMgr.h"
#include "CharacterDatabaseCleaner.h"
+#include "CharacterPackets.h"
#include "Chat.h"
#include "Common.h"
#include "ConditionMgr.h"
@@ -930,7 +931,7 @@ void Player::CleanupsBeforeDelete(bool finalCleanup)
itr->second.save->RemovePlayer(this);
}
-bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo)
+bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::CharacterCreateInfo const* createInfo)
{
//FIXME: outfitId not used in player creating
/// @todo need more checks against packet modifications
@@ -970,14 +971,14 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
setFactionForRace(createInfo->Race);
- if (!IsValidGender(createInfo->Gender))
+ if (!IsValidGender(createInfo->Sex))
{
TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid gender (%u) - refusing to do so",
- GetSession()->GetAccountId(), m_name.c_str(), createInfo->Gender);
+ GetSession()->GetAccountId(), m_name.c_str(), createInfo->Sex);
return false;
}
- uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16);
+ uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Sex << 16);
SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24)));
InitDisplayIds();
@@ -993,11 +994,11 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); // -1 is default value
SetUInt32Value(PLAYER_BYTES, (createInfo->Skin | (createInfo->Face << 8) | (createInfo->HairStyle << 16) | (createInfo->HairColor << 24)));
- SetUInt32Value(PLAYER_BYTES_2, (createInfo->FacialHair |
+ SetUInt32Value(PLAYER_BYTES_2, (createInfo->FacialHairStyle |
(0x00 << 8) |
(0x00 << 16) |
(((GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NOT_RAF_LINKED) << 24)));
- SetByteValue(PLAYER_BYTES_3, 0, createInfo->Gender);
+ SetByteValue(PLAYER_BYTES_3, 0, createInfo->Sex);
SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1)
SetGuidValue(OBJECT_FIELD_DATA, ObjectGuid::Empty);
@@ -1121,7 +1122,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
addActionButton(action_itr->button, action_itr->action, action_itr->type);
// original items
- if (CharStartOutfitEntry const* oEntry = GetCharStartOutfitEntry(createInfo->Race, createInfo->Class, createInfo->Gender))
+ if (CharStartOutfitEntry const* oEntry = GetCharStartOutfitEntry(createInfo->Race, createInfo->Class, createInfo->Sex))
{
for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j)
{
@@ -20242,7 +20243,7 @@ void Player::SetUInt32ValueInArray(Tokenizer& Tokenizer, uint16 index, uint32 va
Tokenizer[index] = buf;
}
-void Player::Customize(CharacterCustomizeInfo const* customizeInfo, SQLTransaction& trans)
+void Player::Customize(WorldPackets::Character::CharacterCustomizeInfo const* customizeInfo, SQLTransaction& trans)
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PLAYERBYTES2);
stmt->setUInt64(0, customizeInfo->Guid.GetCounter());
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 74222bd162f..8509ec2bcf1 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -44,7 +44,6 @@ struct VendorItem;
template<class T> class AchievementMgr;
class ReputationMgr;
class Channel;
-class CharacterCreateInfo;
class Creature;
class DynamicObject;
class Group;
@@ -56,8 +55,6 @@ class PlayerSocial;
class SpellCastTargets;
class UpdateMask;
-struct CharacterCustomizeInfo;
-
typedef std::deque<Mail*> PlayerMails;
#define PLAYER_MAX_SKILLS 128
@@ -1289,7 +1286,7 @@ class Player : public Unit, public GridObject<Player>
void SetSummonPoint(uint32 mapid, float x, float y, float z);
void SummonIfPossible(bool agree);
- bool Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo);
+ bool Create(ObjectGuid::LowType guidlow, WorldPackets::Character::CharacterCreateInfo const* createInfo);
void Update(uint32 time) override;
@@ -1711,7 +1708,7 @@ class Player : public Unit, public GridObject<Player>
static void SetUInt32ValueInArray(Tokenizer& data, uint16 index, uint32 value);
static void SetFloatValueInArray(Tokenizer& data, uint16 index, float value);
- static void Customize(CharacterCustomizeInfo const* customizeInfo, SQLTransaction& trans);
+ static void Customize(WorldPackets::Character::CharacterCustomizeInfo const* customizeInfo, SQLTransaction& trans);
static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, SQLTransaction& trans);
static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars = true, bool deleteFinally = false);
diff --git a/src/server/game/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp
index 9b14a8eef81..8cde824c26e 100644
--- a/src/server/game/Handlers/AuthHandler.cpp
+++ b/src/server/game/Handlers/AuthHandler.cpp
@@ -20,6 +20,7 @@
#include "WorldSession.h"
#include "WorldPacket.h"
#include "AuthenticationPackets.h"
+#include "SystemPackets.h"
void WorldSession::SendAuthResponse(uint8 code, bool queued, uint32 queuePos)
{
@@ -64,7 +65,7 @@ void WorldSession::SendAuthWaitQue(uint32 position)
response.WaitInfo.value.WaitCount = position;
response.Result = AUTH_WAIT_QUEUE;
}
-
+
response.Write();
SendPacket(&response.GetWorldPacket());
}
@@ -75,3 +76,26 @@ void WorldSession::SendClientCacheVersion(uint32 version)
data << uint32(version);
SendPacket(&data);
}
+
+void WorldSession::SendSetTimeZoneInformation()
+{
+ /// @todo: replace dummy values
+ WorldPackets::System::SetTimeZoneInformation packet;
+ packet.ServerTimeTZ = "Europe/Paris";
+ packet.GameTimeTZ = "Europe/Paris";
+
+ packet.Write();
+ SendPacket(&packet.GetWorldPacket());
+}
+
+void WorldSession::SendFeatureSystemStatusGlueScreen()
+{
+ WorldPackets::System::FeatureSystemStatusGlueScreen features;
+ features.BpayStoreAvailable = false;
+ features.BpayStoreDisabledByParentalControls = false;
+ features.CharUndeleteEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED);
+ features.BpayStoreEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED);
+
+ features.Write();
+ SendPacket(&features.GetWorldPacket());
+}
diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index e5f537426cf..5104be43e59 100644
--- a/src/server/game/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
@@ -149,7 +149,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_LFG_CANT_USE_BATTLEGROUND);
- GetPlayer()->GetSession()->SendPacket(&data);
+ SendPacket(&data);
return;
}
@@ -158,7 +158,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
- _player->GetSession()->SendPacket(&data);
+ SendPacket(&data);
return;
}
@@ -167,7 +167,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
// player is already in random queue
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_RANDOM_BG);
- _player->GetSession()->SendPacket(&data);
+ SendPacket(&data);
return;
}
@@ -176,7 +176,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
// player is already in queue, can't start random queue
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_NON_RANDOM_BG);
- _player->GetSession()->SendPacket(&data);
+ SendPacket(&data);
return;
}
@@ -190,7 +190,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_BATTLEGROUND_TOO_MANY_QUEUES);
- _player->GetSession()->SendPacket(&data);
+ SendPacket(&data);
return;
}
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index c5d5f5540d5..8593b4352c3 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -227,10 +227,10 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result)
charEnum.Success = true;
charEnum.IsDeletedCharacters = false;
+ _legitCharacters.clear();
+
if (result)
{
- _legitCharacters.clear();
-
do
{
Field* fields = result->Fetch();
@@ -270,39 +270,59 @@ void WorldSession::HandleCharEnumOpcode(WorldPacket& /*recvData*/)
stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
stmt->setUInt32(1, GetAccountId());
- _charEnumCallback = CharacterDatabase.AsyncQuery(stmt);
+ _charEnumCallback.SetParam(false);
+ _charEnumCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
}
-void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
+void WorldSession::HandleCharUndeleteEnum(PreparedQueryResult result)
{
- CharacterCreateInfo createInfo;
+ WorldPackets::Character::CharEnumResult charEnum;
+ charEnum.Success = true;
+ charEnum.IsDeletedCharacters = true;
- uint32 nameLength = recvData.ReadBits(6);
- bool hasTempalte = recvData.ReadBit();
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ WorldPackets::Character::CharEnumResult::CharacterInfo charInfo(fields);
- recvData >> createInfo.Race
- >> createInfo.Class
- >> createInfo.Gender
- >> createInfo.Skin
- >> createInfo.Face
- >> createInfo.HairStyle
- >> createInfo.HairColor
- >> createInfo.FacialHair
- >> createInfo.OutfitId;
+ TC_LOG_INFO("network", "Loading undeleted char guid %s from account %u.", charInfo.Guid.ToString().c_str(), GetAccountId());
- createInfo.Name = recvData.ReadString(nameLength);
+ charEnum.Characters.emplace_back(charInfo);
+ }
+ while (result->NextRow());
+ }
- if (hasTempalte)
- recvData.read_skip<uint32>(); // Template from SMSG_AUTH_RESPONSE
+ charEnum.Write();
+ SendPacket(&charEnum.GetWorldPacket());
+}
+void WorldSession::HandleCharUndeleteEnumOpcode(WorldPacket& /*recvData*/)
+{
+ /// get all the data necessary for loading all undeleted characters (along with their pets) on the account
+ PreparedStatement* stmt = nullptr;
+ if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME);
+ else
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_UNDELETE_ENUM);
+ stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
+ stmt->setUInt32(1, GetAccountId());
+
+ _charEnumCallback.SetParam(true);
+ _charEnumCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
+}
+
+void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CharacterCreate& charCreate)
+{
if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK))
{
if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED))
{
bool disabled = false;
- switch (Player::TeamForRace(createInfo.Race))
+ switch (Player::TeamForRace(charCreate.CreateInfo->Race))
{
case ALLIANCE:
disabled = (mask & (1 << 0)) != 0;
@@ -320,18 +340,18 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
}
}
- ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(createInfo.Class);
+ ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(charCreate.CreateInfo->Class);
if (!classEntry)
{
- TC_LOG_ERROR("network", "Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", createInfo.Class, GetAccountId());
+ TC_LOG_ERROR("network", "Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", charCreate.CreateInfo->Class, GetAccountId());
SendCharCreate(CHAR_CREATE_FAILED);
return;
}
- ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(createInfo.Race);
+ ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(charCreate.CreateInfo->Race);
if (!raceEntry)
{
- TC_LOG_ERROR("network", "Race (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", createInfo.Race, GetAccountId());
+ TC_LOG_ERROR("network", "Race (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", charCreate.CreateInfo->Race, GetAccountId());
SendCharCreate(CHAR_CREATE_FAILED);
return;
}
@@ -339,7 +359,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
// prevent character creating Expansion race without Expansion account
if (raceEntry->expansion > Expansion())
{
- TC_LOG_ERROR("network", "Expansion %u account:[%d] tried to Create character with expansion %u race (%u)", Expansion(), GetAccountId(), raceEntry->expansion, createInfo.Race);
+ TC_LOG_ERROR("network", "Expansion %u account:[%d] tried to Create character with expansion %u race (%u)", Expansion(), GetAccountId(), raceEntry->expansion, charCreate.CreateInfo->Race);
SendCharCreate(CHAR_CREATE_EXPANSION);
return;
}
@@ -347,7 +367,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
// prevent character creating Expansion class without Expansion account
if (classEntry->expansion > Expansion())
{
- TC_LOG_ERROR("network", "Expansion %u account:[%d] tried to Create character with expansion %u class (%u)", Expansion(), GetAccountId(), classEntry->expansion, createInfo.Class);
+ TC_LOG_ERROR("network", "Expansion %u account:[%d] tried to Create character with expansion %u class (%u)", Expansion(), GetAccountId(), classEntry->expansion, charCreate.CreateInfo->Class);
SendCharCreate(CHAR_CREATE_EXPANSION_CLASS);
return;
}
@@ -355,7 +375,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK))
{
uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK);
- if ((1 << (createInfo.Race - 1)) & raceMaskDisabled)
+ if ((1 << (charCreate.CreateInfo->Race - 1)) & raceMaskDisabled)
{
SendCharCreate(CHAR_CREATE_DISABLED);
return;
@@ -365,7 +385,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK))
{
uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK);
- if ((1 << (createInfo.Class - 1)) & classMaskDisabled)
+ if ((1 << (charCreate.CreateInfo->Class - 1)) & classMaskDisabled)
{
SendCharCreate(CHAR_CREATE_DISABLED);
return;
@@ -373,7 +393,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
}
// prevent character creating with invalid name
- if (!normalizePlayerName(createInfo.Name))
+ if (!normalizePlayerName(charCreate.CreateInfo->Name))
{
TC_LOG_ERROR("network", "Account:[%d] but tried to Create character with empty [name] ", GetAccountId());
SendCharCreate(CHAR_NAME_NO_NAME);
@@ -381,32 +401,30 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
}
// check name limitations
- ResponseCodes res = ObjectMgr::CheckPlayerName(createInfo.Name, true);
+ ResponseCodes res = ObjectMgr::CheckPlayerName(charCreate.CreateInfo->Name, true);
if (res != CHAR_NAME_SUCCESS)
{
SendCharCreate(res);
return;
}
- if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(createInfo.Name))
+ if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(charCreate.CreateInfo->Name))
{
SendCharCreate(CHAR_NAME_RESERVED);
return;
}
- if (createInfo.Class == CLASS_DEATH_KNIGHT && !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_HEROIC_CHARACTER))
+ if (charCreate.CreateInfo->Class == CLASS_DEATH_KNIGHT && !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_HEROIC_CHARACTER))
{
// speedup check for heroic class disabled case
- uint32 heroic_free_slots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM);
- if (heroic_free_slots == 0)
+ if (!sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM))
{
SendCharCreate(CHAR_CREATE_UNIQUE_CLASS_LIMIT);
return;
}
// speedup check for heroic class disabled case
- uint32 req_level_for_heroic = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER);
- if (req_level_for_heroic > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
+ if (sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER) > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
{
SendCharCreate(CHAR_CREATE_LEVEL_REQUIREMENT);
return;
@@ -414,18 +432,17 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
}
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME);
- stmt->setString(0, createInfo.Name);
+ stmt->setString(0, charCreate.CreateInfo->Name);
- delete _charCreateCallback.GetParam(); // Delete existing if any, to make the callback chain reset to stage 0
- _charCreateCallback.SetParam(new CharacterCreateInfo(std::move(createInfo)));
+ _charCreateCallback.SetParam(charCreate.CreateInfo);
_charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
}
-void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, CharacterCreateInfo* createInfo)
+void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPackets::Character::CharacterCreateInfo* createInfo)
{
/** This is a series of callbacks executed consecutively as a result from the database becomes available.
This is much more efficient than synchronous requests on packet handler, and much less DoS prone.
- It also prevents data syncrhonisation errors.
+ It also prevents data synchronisation errors.
*/
switch (_charCreateCallback.GetStage())
{
@@ -434,12 +451,11 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
if (result)
{
SendCharCreate(CHAR_CREATE_NAME_IN_USE);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
- ASSERT(_charCreateCallback.GetParam() == createInfo);
+ ASSERT(_charCreateCallback.GetParam().get() == createInfo);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SUM_REALM_CHARACTERS);
stmt->setUInt32(0, GetAccountId());
@@ -464,12 +480,11 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT))
{
SendCharCreate(CHAR_CREATE_ACCOUNT_LIMIT);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
- ASSERT(_charCreateCallback.GetParam() == createInfo);
+ ASSERT(_charCreateCallback.GetParam().get() == createInfo);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS);
stmt->setUInt32(0, GetAccountId());
@@ -489,7 +504,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
{
SendCharCreate(CHAR_CREATE_SERVER_LIMIT);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
@@ -542,7 +556,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
if (freeHeroicSlots == 0)
{
SendCharCreate(CHAR_CREATE_UNIQUE_CLASS_LIMIT);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
@@ -567,7 +580,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
if (accTeam != team)
{
SendCharCreate(CHAR_CREATE_PVP_TEAMS_VIOLATION);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
@@ -597,7 +609,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
if (freeHeroicSlots == 0)
{
SendCharCreate(CHAR_CREATE_UNIQUE_CLASS_LIMIT);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
@@ -616,7 +627,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
if (checkHeroicReqs && !hasHeroicReqLevel)
{
SendCharCreate(CHAR_CREATE_LEVEL_REQUIREMENT);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
@@ -629,7 +639,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
newChar.CleanupsBeforeDelete();
SendCharCreate(CHAR_CREATE_ERROR);
- delete createInfo;
_charCreateCallback.Reset();
return;
}
@@ -665,50 +674,46 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
sWorld->AddCharacterNameData(newChar.GetGUID(), newChar.GetName(), newChar.getGender(), newChar.getRace(), newChar.getClass(), newChar.getLevel());
newChar.CleanupsBeforeDelete();
- delete createInfo;
_charCreateCallback.Reset();
break;
}
}
}
-void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
+void WorldSession::HandleCharDeleteOpcode(WorldPackets::Character::CharacterDelete& charDelete)
{
- ObjectGuid guid;
- recvData >> guid;
-
// Initiating
uint32 initAccountId = GetAccountId();
// can't delete loaded character
- if (ObjectAccessor::FindPlayer(guid))
+ if (ObjectAccessor::FindPlayer(charDelete.Guid))
{
- sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
+ sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
return;
}
- uint32 accountId = 0;
- uint8 level = 0;
- std::string name;
-
// is guild leader
- if (sGuildMgr->GetGuildByLeader(guid))
+ if (sGuildMgr->GetGuildByLeader(charDelete.Guid))
{
- sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
+ sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
SendCharDelete(CHAR_DELETE_FAILED_GUILD_LEADER);
return;
}
// is arena team captain
- if (sArenaTeamMgr->GetArenaTeamByCaptain(guid))
+ if (sArenaTeamMgr->GetArenaTeamByCaptain(charDelete.Guid))
{
- sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
+ sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
SendCharDelete(CHAR_DELETE_FAILED_ARENA_CAPTAIN);
return;
}
+ uint32 accountId = 0;
+ uint8 level = 0;
+ std::string name;
+
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DATA_BY_GUID);
- stmt->setUInt64(0, guid.GetCounter());
+ stmt->setUInt64(0, charDelete.Guid.GetCounter());
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
{
@@ -721,26 +726,26 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
// prevent deleting other players' characters using cheating tools
if (accountId != initAccountId)
{
- sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
+ sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
return;
}
- TC_LOG_INFO("entities.player.character", "Account: %u, IP: %s deleted character: %s, %s, Level: %u", accountId, GetRemoteAddress().c_str(), name.c_str(), guid.ToString().c_str(), level);
+ TC_LOG_INFO("entities.player.character", "Account: %u, IP: %s deleted character: %s, %s, Level: %u", accountId, GetRemoteAddress().c_str(), name.c_str(), charDelete.Guid.ToString().c_str(), level);
// To prevent hook failure, place hook before removing reference from DB
- sScriptMgr->OnPlayerDelete(guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete.
+ sScriptMgr->OnPlayerDelete(charDelete.Guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete.
// Shouldn't interfere with character deletion though
if (sLog->ShouldLog("entities.player.dump", LOG_LEVEL_INFO)) // optimize GetPlayerDump call
{
std::string dump;
- if (PlayerDumpWriter().GetDump(guid.GetCounter(), dump))
- sLog->outCharDump(dump.c_str(), accountId, guid.GetCounter(), name.c_str());
+ if (PlayerDumpWriter().GetDump(charDelete.Guid.GetCounter(), dump))
+ sLog->outCharDump(dump.c_str(), accountId, charDelete.Guid.GetCounter(), name.c_str());
}
- sGuildFinderMgr->RemoveAllMembershipRequestsFromPlayer(guid);
- sCalendarMgr->RemoveAllPlayerEventsAndInvites(guid);
- Player::DeleteFromDB(guid, accountId);
+ sGuildFinderMgr->RemoveAllMembershipRequestsFromPlayer(charDelete.Guid);
+ sCalendarMgr->RemoveAllPlayerEventsAndInvites(charDelete.Guid);
+ Player::DeleteFromDB(charDelete.Guid, accountId);
SendCharDelete(CHAR_DELETE_SUCCESS);
}
@@ -1156,7 +1161,7 @@ void WorldSession::HandleShowingCloakOpcode(WorldPacket& recvData)
void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData)
{
- CharacterRenameInfo renameInfo;
+ WorldPackets::Character::CharacterRenameInfo renameInfo;
recvData >> renameInfo.Guid
>> renameInfo.Name;
@@ -1193,11 +1198,11 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData)
stmt->setString(4, renameInfo.Name);
delete _charRenameCallback.GetParam();
- _charRenameCallback.SetParam(new CharacterRenameInfo(std::move(renameInfo)));
+ _charRenameCallback.SetParam(new WorldPackets::Character::CharacterRenameInfo(std::move(renameInfo)));
_charRenameCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
}
-void WorldSession::HandleChangePlayerNameOpcodeCallBack(PreparedQueryResult result, CharacterRenameInfo const* renameInfo)
+void WorldSession::HandleCharRenameCallBack(PreparedQueryResult result, WorldPackets::Character::CharacterRenameInfo const* renameInfo)
{
if (!result)
{
@@ -1394,7 +1399,7 @@ void WorldSession::HandleRemoveGlyph(WorldPacket& recvData)
void WorldSession::HandleCharCustomize(WorldPacket& recvData)
{
- CharacterCustomizeInfo customizeInfo;
+ WorldPackets::Character::CharacterCustomizeInfo customizeInfo;
recvData >> customizeInfo.Guid;
if (!IsLegitCharacterForAccount(customizeInfo.Guid))
@@ -1625,7 +1630,7 @@ void WorldSession::HandleEquipmentSetUse(WorldPacket& recvData)
void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
{
- CharacterFactionChangeInfo factionChangeInfo;
+ WorldPackets::Character::CharacterFactionChangeInfo factionChangeInfo;
recvData >> factionChangeInfo.Guid;
if (!IsLegitCharacterForAccount(factionChangeInfo.Guid))
@@ -2240,21 +2245,216 @@ void WorldSession::HandleOpeningCinematic(WorldPacket& /*recvData*/)
}
}
+void WorldSession::HandleUndeleteCooldownStatusQuery(WorldPacket& /*recvData*/)
+{
+ /// empty result to force wait
+ PreparedQueryResultPromise result;
+ result.set_value(PreparedQueryResult(nullptr));
+ _undeleteCooldownStatusCallback.SetFutureResult(result.get_future());
+}
+
+void WorldSession::HandleUndeleteCooldownStatusCallback(PreparedQueryResult result)
+{
+ switch (_undeleteCooldownStatusCallback.GetStage())
+ {
+ case 0:
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE);
+ stmt->setUInt32(0, GetBattlenetAccountId());
+
+ _undeleteCooldownStatusCallback.FreeResult();
+ _undeleteCooldownStatusCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt));
+ _undeleteCooldownStatusCallback.NextStage();
+ break;
+ }
+ case 1:
+ {
+ uint32 cooldown = 0;
+ uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN);
+ if (result)
+ {
+ uint32 lastUndelete = result->Fetch()[0].GetUInt32();
+ if (lastUndelete)
+ cooldown = uint32(std::max<int32>(0, int32(lastUndelete) + maxCooldown - time(nullptr)));
+ }
+
+ SendUndeleteCooldownStatusResponse(cooldown, maxCooldown);
+ _undeleteCooldownStatusCallback.Reset();
+ break;
+ }
+ }
+
+}
+
+void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCharacter& undeleteInfo)
+{
+ if (!sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED))
+ {
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_DISABLED, undeleteInfo.UndeleteInfo.get());
+ return;
+ }
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE);
+ stmt->setUInt32(0, GetBattlenetAccountId());
+
+ _charUndeleteCallback.SetParam(undeleteInfo.UndeleteInfo);
+ _charUndeleteCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt));
+ _charUndeleteCallback.NextStage();
+}
+
+void WorldSession::HandleCharUndeleteCallback(PreparedQueryResult result, WorldPackets::Character::CharacterUndeleteInfo* undeleteInfo)
+{
+ /** This is a series of callbacks executed consecutively as a result from the database becomes available.
+ * This is much more efficient than synchronous requests on packet handler.
+ * It also prevents data synchronisation errors.
+ */
+
+ ASSERT(_charUndeleteCallback.GetParam().get() == undeleteInfo);
+
+ switch (_charUndeleteCallback.GetStage())
+ {
+ case 1:
+ {
+ if (result)
+ {
+ uint32 lastUndelete = result->Fetch()[0].GetUInt32();
+ uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN);
+ if (lastUndelete && (lastUndelete + maxCooldown > time(nullptr)))
+ {
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN, undeleteInfo);
+ _charUndeleteCallback.Reset();
+ return;
+ }
+ }
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID);
+ stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter());
+
+ _charUndeleteCallback.FreeResult();
+ _charUndeleteCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
+ _charUndeleteCallback.NextStage();
+ break;
+ }
+ case 2:
+ {
+ if (!result)
+ {
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo);
+ _charUndeleteCallback.Reset();
+ return;
+ }
+
+ Field* fields = result->Fetch();
+ undeleteInfo->Name = fields[1].GetString();
+ uint32 account = fields[2].GetUInt32();
+
+ if (account != GetAccountId())
+ {
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN, undeleteInfo);
+ _charUndeleteCallback.Reset();
+ return;
+ }
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME);
+ stmt->setString(0, undeleteInfo->Name);
+
+ _charUndeleteCallback.FreeResult();
+ _charUndeleteCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
+ _charUndeleteCallback.NextStage();
+ break;
+ }
+ case 3:
+ {
+ if (result)
+ {
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT, undeleteInfo);
+ _charUndeleteCallback.Reset();
+ return;
+ }
+
+ /// @todo: add more safety checks
+ /// * max char count per account
+ /// * max heroic char count
+ /// * team violation
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS);
+ stmt->setUInt32(0, GetAccountId());
+
+ _charUndeleteCallback.FreeResult();
+ _charUndeleteCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
+ _charUndeleteCallback.NextStage();
+ break;
+ }
+ case 4:
+ {
+ if (result)
+ {
+ Field* fields = result->Fetch();
+
+ if (fields[0].GetUInt64() >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
+ {
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo);
+ _charUndeleteCallback.Reset();
+ return;
+ }
+ }
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_RESTORE_DELETE_INFO);
+ stmt->setString(0, undeleteInfo->Name);
+ stmt->setUInt32(1, GetAccountId());
+ stmt->setUInt64(2, undeleteInfo->CharacterGuid.GetCounter());
+ CharacterDatabase.Execute(stmt);
+
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_CHAR_UNDELETE);
+ stmt->setUInt32(0, GetBattlenetAccountId());
+ LoginDatabase.Execute(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_NAME_DATA);
+ stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter());
+
+ _charUndeleteCallback.FreeResult();
+ _charUndeleteCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt));
+ _charUndeleteCallback.NextStage();
+ break;
+ }
+ case 5:
+ {
+ if (!result)
+ {
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN, undeleteInfo);
+ _charUndeleteCallback.Reset();
+ return;
+ }
+
+ Field* fields = result->Fetch();
+ sWorld->AddCharacterNameData(undeleteInfo->CharacterGuid, undeleteInfo->Name, fields[2].GetUInt8(), fields[0].GetUInt8(), fields[1].GetUInt8(), fields[3].GetUInt8());
+
+ SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_OK, undeleteInfo);
+ _charUndeleteCallback.Reset();
+ break;
+ }
+ }
+}
+
void WorldSession::SendCharCreate(ResponseCodes result)
{
- WorldPacket data(SMSG_CHAR_CREATE, 1);
- data << uint8(result);
- SendPacket(&data);
+ WorldPackets::Character::CharacterCreateResponse response;
+ response.Code = result;
+
+ response.Write();
+ SendPacket(&response.GetWorldPacket());
}
void WorldSession::SendCharDelete(ResponseCodes result)
{
- WorldPacket data(SMSG_CHAR_DELETE, 1);
- data << uint8(result);
- SendPacket(&data);
+ WorldPackets::Character::CharacterDeleteResponse response;
+ response.Code = result;
+
+ response.Write();
+ SendPacket(&response.GetWorldPacket());
}
-void WorldSession::SendCharRename(ResponseCodes result, CharacterRenameInfo const& renameInfo)
+void WorldSession::SendCharRename(ResponseCodes result, WorldPackets::Character::CharacterRenameInfo const& renameInfo)
{
WorldPacket data(SMSG_CHAR_RENAME, 1 + 8 + renameInfo.Name.size() + 1);
data << uint8(result);
@@ -2266,7 +2466,7 @@ void WorldSession::SendCharRename(ResponseCodes result, CharacterRenameInfo cons
SendPacket(&data);
}
-void WorldSession::SendCharCustomize(ResponseCodes result, CharacterCustomizeInfo const& customizeInfo)
+void WorldSession::SendCharCustomize(ResponseCodes result, WorldPackets::Character::CharacterCustomizeInfo const& customizeInfo)
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1 + 8 + customizeInfo.Name.size() + 1 + 6);
data << uint8(result);
@@ -2284,7 +2484,7 @@ void WorldSession::SendCharCustomize(ResponseCodes result, CharacterCustomizeInf
SendPacket(&data);
}
-void WorldSession::SendCharFactionChange(ResponseCodes result, CharacterFactionChangeInfo const& factionChangeInfo)
+void WorldSession::SendCharFactionChange(ResponseCodes result, WorldPackets::Character::CharacterFactionChangeInfo const& factionChangeInfo)
{
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1 + 8 + factionChangeInfo.Name.size() + 1 + 7);
data << uint8(result);
@@ -2318,3 +2518,24 @@ void WorldSession::SendBarberShopResult(BarberShopResult result)
data << uint32(result);
SendPacket(&data);
}
+
+void WorldSession::SendUndeleteCooldownStatusResponse(uint32 currentCooldown, uint32 maxCooldown)
+{
+ WorldPackets::Character::UndeleteCooldownStatusResponse response;
+ response.OnCooldown = (currentCooldown > 0);
+ response.MaxCooldown = maxCooldown;
+ response.CurrentCooldown = currentCooldown;
+
+ response.Write();
+ SendPacket(&response.GetWorldPacket());
+}
+
+void WorldSession::SendUndeleteCharacterResponse(CharacterUndeleteResult result, WorldPackets::Character::CharacterUndeleteInfo const* undeleteInfo)
+{
+ WorldPackets::Character::UndeleteCharacterResponse response;
+ response.UndeleteInfo = undeleteInfo;
+ response.Result = result;
+
+ response.Write();
+ SendPacket(&response.GetWorldPacket());
+}
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 097ac61ec8a..e2c82763161 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -4324,45 +4324,58 @@ enum ResponseCodes
CHAR_CREATE_CHARACTER_RACE_ONLY = 67,
CHAR_CREATE_CHARACTER_GOLD_LIMIT = 68,
CHAR_CREATE_FORCE_LOGIN = 69,
+ CHAR_CREATE_TRIAL = 70,
+
+ CHAR_DELETE_IN_PROGRESS = 71,
+ CHAR_DELETE_SUCCESS = 72,
+ CHAR_DELETE_FAILED = 73,
+ CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 74,
+ CHAR_DELETE_FAILED_GUILD_LEADER = 75,
+ CHAR_DELETE_FAILED_ARENA_CAPTAIN = 76,
+ CHAR_DELETE_FAILED_HAS_HEIRLOOM_OR_MAIL = 77,
+
+ CHAR_LOGIN_IN_PROGRESS = 78,
+ CHAR_LOGIN_SUCCESS = 79,
+ CHAR_LOGIN_NO_WORLD = 80,
+ CHAR_LOGIN_DUPLICATE_CHARACTER = 81,
+ CHAR_LOGIN_NO_INSTANCES = 82,
+ CHAR_LOGIN_FAILED = 83,
+ CHAR_LOGIN_DISABLED = 84,
+ CHAR_LOGIN_NO_CHARACTER = 85,
+ CHAR_LOGIN_LOCKED_FOR_TRANSFER = 86,
+ CHAR_LOGIN_LOCKED_BY_BILLING = 87,
+ CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 88,
+ CHAR_LOGIN_TEMPORARY_GM_LOCK = 89,
+ CHAR_LOGIN_LOCKED_BY_CHARACTER_UPGRADE = 90,
+ CHAR_LOGIN_LOCKED_BY_REVOKED_CHARACTER_UPGRADE = 91,
+
+ CHAR_NAME_SUCCESS = 92,
+ CHAR_NAME_FAILURE = 93,
+ CHAR_NAME_NO_NAME = 94,
+ CHAR_NAME_TOO_SHORT = 95,
+ CHAR_NAME_TOO_LONG = 96,
+ CHAR_NAME_INVALID_CHARACTER = 97,
+ CHAR_NAME_MIXED_LANGUAGES = 98,
+ CHAR_NAME_PROFANE = 99,
+ CHAR_NAME_RESERVED = 100,
+ CHAR_NAME_INVALID_APOSTROPHE = 101,
+ CHAR_NAME_MULTIPLE_APOSTROPHES = 102,
+ CHAR_NAME_THREE_CONSECUTIVE = 103,
+ CHAR_NAME_INVALID_SPACE = 104,
+ CHAR_NAME_CONSECUTIVE_SPACES = 105,
+ CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 106,
+ CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 107,
+ CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 108
+};
- CHAR_DELETE_IN_PROGRESS = 70,
- CHAR_DELETE_SUCCESS = 71,
- CHAR_DELETE_FAILED = 72,
- CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 73,
- CHAR_DELETE_FAILED_GUILD_LEADER = 74,
- CHAR_DELETE_FAILED_ARENA_CAPTAIN = 75,
- CHAR_DELETE_FAILED_HAS_HEIRLOOM_OR_MAIL = 76,
-
- CHAR_LOGIN_IN_PROGRESS = 77,
- CHAR_LOGIN_SUCCESS = 78,
- CHAR_LOGIN_NO_WORLD = 79,
- CHAR_LOGIN_DUPLICATE_CHARACTER = 80,
- CHAR_LOGIN_NO_INSTANCES = 81,
- CHAR_LOGIN_FAILED = 82,
- CHAR_LOGIN_DISABLED = 83,
- CHAR_LOGIN_NO_CHARACTER = 84,
- CHAR_LOGIN_LOCKED_FOR_TRANSFER = 85,
- CHAR_LOGIN_LOCKED_BY_BILLING = 86,
- CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 87,
- CHAR_LOGIN_TEMPORARY_GM_LOCK = 88,
-
- CHAR_NAME_SUCCESS = 89,
- CHAR_NAME_FAILURE = 90,
- CHAR_NAME_NO_NAME = 91,
- CHAR_NAME_TOO_SHORT = 92,
- CHAR_NAME_TOO_LONG = 93,
- CHAR_NAME_INVALID_CHARACTER = 94,
- CHAR_NAME_MIXED_LANGUAGES = 95,
- CHAR_NAME_PROFANE = 96,
- CHAR_NAME_RESERVED = 97,
- CHAR_NAME_INVALID_APOSTROPHE = 98,
- CHAR_NAME_MULTIPLE_APOSTROPHES = 99,
- CHAR_NAME_THREE_CONSECUTIVE = 100,
- CHAR_NAME_INVALID_SPACE = 101,
- CHAR_NAME_CONSECUTIVE_SPACES = 102,
- CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 103,
- CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 104,
- CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 105,
+enum CharacterUndeleteResult
+{
+ CHARACTER_UNDELETE_RESULT_OK = 0,
+ CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN = 1,
+ CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE = 2,
+ CHARACTER_UNDELETE_RESULT_ERROR_DISABLED = 3,
+ CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT = 4,
+ CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN = 5
};
/// Ban function modes
diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h
index 305a841d4e7..209300e023e 100644
--- a/src/server/game/Server/Packets/AuthenticationPackets.h
+++ b/src/server/game/Server/Packets/AuthenticationPackets.h
@@ -29,7 +29,7 @@ namespace WorldPackets
class AuthChallenge final : public ServerPacket
{
public:
- AuthChallenge() : ServerPacket(SMSG_AUTH_CHALLENGE, 8 + 32 + 1), Challenge(0) { }
+ AuthChallenge() : ServerPacket(SMSG_AUTH_CHALLENGE, 4 + 32 + 1), Challenge(0) { }
void Write() override;
diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp
index ff44777ac79..095eb452e2b 100644
--- a/src/server/game/Server/Packets/CharacterPackets.cpp
+++ b/src/server/game/Server/Packets/CharacterPackets.cpp
@@ -37,8 +37,8 @@ WorldPackets::Character::CharEnumResult::CharacterInfo::CharacterInfo(Field* fie
HairColor = uint8((fields[5].GetUInt32() >> 24) & 0xFF);
FacialHair = uint8(fields[6].GetUInt32() & 0xFF);
Level = fields[7].GetUInt8();
- ZoneId = fields[8].GetUInt16();
- MapId = fields[9].GetUInt16();
+ ZoneId = int32(fields[8].GetUInt16());
+ MapId = int32(fields[9].GetUInt16());
PreLoadPosition.x = fields[10].GetFloat();
PreLoadPosition.y = fields[11].GetFloat();
PreLoadPosition.z = fields[12].GetFloat();
@@ -147,8 +147,8 @@ void WorldPackets::Character::CharEnumResult::Write()
_worldPacket << uint8(charInfo.HairColor);
_worldPacket << uint8(charInfo.FacialHair);
_worldPacket << uint8(charInfo.Level);
- _worldPacket << uint32(charInfo.ZoneId);
- _worldPacket << uint32(charInfo.MapId);
+ _worldPacket << int32(charInfo.ZoneId);
+ _worldPacket << int32(charInfo.MapId);
_worldPacket << float(charInfo.PreLoadPosition.x);
_worldPacket << float(charInfo.PreLoadPosition.y);
_worldPacket << float(charInfo.PreLoadPosition.z);
@@ -178,11 +178,97 @@ void WorldPackets::Character::CharEnumResult::Write()
for (RestrictedFactionChangeRuleInfo const& rule : FactionChangeRestrictions)
{
- _worldPacket << uint32(rule.Mask);
+ _worldPacket << int32(rule.Mask);
_worldPacket << uint8(rule.Race);
}
}
+WorldPackets::Character::CharacterCreate::CharacterCreate(WorldPacket&& packet)
+ : ClientPacket(std::move(packet))
+{
+ ASSERT(_worldPacket.GetOpcode() == CMSG_CHAR_CREATE);
+}
+
+void WorldPackets::Character::CharacterCreate::Read()
+{
+ CreateInfo.reset(new CharacterCreateInfo());
+ uint32 nameLength = _worldPacket.ReadBits(6);
+ CreateInfo->TemplateSet.HasValue = _worldPacket.ReadBit();
+ _worldPacket >> CreateInfo->Race;
+ _worldPacket >> CreateInfo->Class;
+ _worldPacket >> CreateInfo->Sex;
+ _worldPacket >> CreateInfo->Skin;
+ _worldPacket >> CreateInfo->Face;
+ _worldPacket >> CreateInfo->HairStyle;
+ _worldPacket >> CreateInfo->HairColor;
+ _worldPacket >> CreateInfo->FacialHairStyle;
+ _worldPacket >> CreateInfo->OutfitId;
+ CreateInfo->Name = _worldPacket.ReadString(nameLength);
+ if (CreateInfo->TemplateSet.HasValue)
+ _worldPacket >> CreateInfo->TemplateSet.value;
+}
+
+WorldPackets::Character::CharacterCreateResponse::CharacterCreateResponse()
+ : ServerPacket(SMSG_CHAR_CREATE, 1) { }
+
+void WorldPackets::Character::CharacterCreateResponse::Write()
+{
+ _worldPacket << uint8(Code);
+}
+
+WorldPackets::Character::CharacterDelete::CharacterDelete(WorldPacket&& packet)
+ : ClientPacket(std::move(packet))
+{
+ ASSERT(_worldPacket.GetOpcode() == CMSG_CHAR_DELETE);
+}
+
+void WorldPackets::Character::CharacterDelete::Read()
+{
+ _worldPacket >> Guid;
+}
+
+WorldPackets::Character::CharacterDeleteResponse::CharacterDeleteResponse()
+ : ServerPacket(SMSG_CHAR_DELETE, 1) { }
+
+void WorldPackets::Character::CharacterDeleteResponse::Write()
+{
+ _worldPacket << uint8(Code);
+}
+
+WorldPackets::Character::UndeleteCharacter::UndeleteCharacter(WorldPacket&& packet)
+ : ClientPacket(std::move(packet))
+{
+ ASSERT(_worldPacket.GetOpcode() == CMSG_UNDELETE_CHARACTER);
+}
+
+void WorldPackets::Character::UndeleteCharacter::Read()
+{
+ UndeleteInfo.reset(new CharacterUndeleteInfo());
+ _worldPacket >> UndeleteInfo->ClientToken;
+ _worldPacket >> UndeleteInfo->CharacterGuid;
+}
+
+WorldPackets::Character::UndeleteCharacterResponse::UndeleteCharacterResponse()
+ : ServerPacket(SMSG_UNDELETE_CHARACTER_RESPONSE, 26) { }
+
+void WorldPackets::Character::UndeleteCharacterResponse::Write()
+{
+ ASSERT(UndeleteInfo);
+ _worldPacket << int32(UndeleteInfo->ClientToken);
+ _worldPacket << uint32(Result);
+ _worldPacket << UndeleteInfo->CharacterGuid;
+}
+
+WorldPackets::Character::UndeleteCooldownStatusResponse::UndeleteCooldownStatusResponse()
+ : ServerPacket(SMSG_UNDELETE_COOLDOWN_STATUS_RESPONSE, 9) { }
+
+void WorldPackets::Character::UndeleteCooldownStatusResponse::Write()
+{
+ _worldPacket.WriteBit(OnCooldown);
+ _worldPacket << uint32(MaxCooldown);
+ _worldPacket << uint32(CurrentCooldown);
+}
+
WorldPackets::Character::PlayerLogin::PlayerLogin(WorldPacket&& packet)
: ClientPacket(std::move(packet))
{
diff --git a/src/server/game/Server/Packets/CharacterPackets.h b/src/server/game/Server/Packets/CharacterPackets.h
index 2f8b069164a..135d53f8e8c 100644
--- a/src/server/game/Server/Packets/CharacterPackets.h
+++ b/src/server/game/Server/Packets/CharacterPackets.h
@@ -25,6 +25,77 @@ namespace WorldPackets
{
namespace Character
{
+ struct CharacterCreateInfo
+ {
+ friend class CharacterCreate;
+ friend class Player;
+ friend class WorldSession;
+
+ protected:
+ /// User specified variables
+ uint8 Race = 0;
+ uint8 Class = 0;
+ uint8 Sex = GENDER_NONE;
+ uint8 Skin = 0;
+ uint8 Face = 0;
+ uint8 HairStyle = 0;
+ uint8 HairColor = 0;
+ uint8 FacialHairStyle = 0;
+ uint8 OutfitId = 0;
+ Optional<int32> TemplateSet;
+ std::string Name;
+
+ /// Server side data
+ uint8 CharCount = 0;
+ };
+
+ struct CharacterRenameInfo
+ {
+ friend class WorldSession;
+
+ protected:
+ ObjectGuid Guid;
+ std::string Name;
+ };
+
+ struct CharacterCustomizeInfo : public CharacterRenameInfo
+ {
+ friend class Player;
+ friend class WorldSession;
+
+ protected:
+ uint8 Gender = GENDER_NONE;
+ uint8 Skin = 0;
+ uint8 Face = 0;
+ uint8 HairStyle = 0;
+ uint8 HairColor = 0;
+ uint8 FacialHair = 0;
+ };
+
+ struct CharacterFactionChangeInfo : public CharacterCustomizeInfo
+ {
+ friend class Player;
+ friend class WorldSession;
+
+ protected:
+ uint8 Race = 0;
+ };
+
+ struct CharacterUndeleteInfo
+ {
+ friend class UndeleteCharacter;
+ friend class UndeleteCharacterResponse;
+ friend class WorldSession;
+
+ protected:
+ /// User specified variables
+ ObjectGuid CharacterGuid; ///< Guid of the character to restore
+ int32 ClientToken = 0; ///< @todo: research
+
+ /// Server side data
+ std::string Name;
+ };
+
class CharEnumResult final : public ServerPacket
{
public:
@@ -51,8 +122,8 @@ namespace WorldPackets
uint8 HairColor = 0;
uint8 FacialHair = 0;
uint8 Level = 0;
- uint32 ZoneId = 0;
- uint32 MapId = 0;
+ int32 ZoneId = 0;
+ int32 MapId = 0;
G3D::Vector3 PreLoadPosition;
ObjectGuid GuildGuid;
uint32 Flags = 0; ///< Character flag @see enum CharacterFlags
@@ -68,7 +139,7 @@ namespace WorldPackets
} Pet;
bool BoostInProgress = false; ///< @todo
- uint32 ProfessionIds[2]; ///< @todo
+ int32 ProfessionIds[2]; ///< @todo
struct VisualItemInfo
{
@@ -82,11 +153,11 @@ namespace WorldPackets
struct RestrictedFactionChangeRuleInfo
{
- RestrictedFactionChangeRuleInfo(uint32 mask, uint8 race)
+ RestrictedFactionChangeRuleInfo(int32 mask, uint8 race)
: Mask(mask), Race(race) { }
- uint32 Mask = 0;
- uint8 Race = 0;
+ int32 Mask = 0;
+ uint8 Race = 0;
};
CharEnumResult();
@@ -100,6 +171,100 @@ namespace WorldPackets
std::list<RestrictedFactionChangeRuleInfo> FactionChangeRestrictions; ///< @todo: research
};
+ class CharacterCreate final : public ClientPacket
+ {
+ public:
+ CharacterCreate(WorldPacket&& packet);
+
+ void Read() override;
+
+ /**
+ * @var uint8 Race
+ * @var uint8 Class
+ * @var uint8 Sex
+ * @var uint8 Skin
+ * @var uint8 Face
+ * @var uint8 HairStyle
+ * @var uint8 HairColor
+ * @var uint8 FacialHairStyle
+ * @var uint8 OutfitId
+ * @var Optional<int32> TemplateSet
+ * @var std::string Name
+ */
+ std::shared_ptr<CharacterCreateInfo> CreateInfo;
+ };
+
+ class CharacterCreateResponse final : public ServerPacket
+ {
+ public:
+ CharacterCreateResponse();
+
+ void Write() override;
+
+ uint8 Code = 0; ///< Result code @see enum ResponseCodes
+ };
+
+ class CharacterDelete final : public ClientPacket
+ {
+ public:
+ CharacterDelete(WorldPacket&& packet);
+
+ void Read() override;
+
+ ObjectGuid Guid; ///< Guid of the character to delete
+ };
+
+ class CharacterDeleteResponse final : public ServerPacket
+ {
+ public:
+ CharacterDeleteResponse();
+
+ void Write() override;
+
+ uint8 Code = 0; ///< Result code @see enum ResponseCodes
+ };
+
+ class UndeleteCharacter final : public ClientPacket
+ {
+ public:
+ UndeleteCharacter(WorldPacket&& packet);
+
+ void Read() override;
+
+ /**
+ * @var ObjectGuid CharacterGuid
+ * @var int32 ClientToken
+ */
+ std::shared_ptr<CharacterUndeleteInfo> UndeleteInfo;
+ };
+
+ class UndeleteCharacterResponse final : public ServerPacket
+ {
+ public:
+ UndeleteCharacterResponse();
+
+ void Write() override;
+
+ /**
+ * @var ObjectGuid CharacterGuid
+ * @var int32 ClientToken
+ */
+ CharacterUndeleteInfo const* UndeleteInfo = nullptr;
+ uint32 Result = 0; ///< @see enum CharacterUndeleteResult
+ };
+
+ class UndeleteCooldownStatusResponse final : public ServerPacket
+ {
+ public:
+ UndeleteCooldownStatusResponse();
+
+ void Write() override;
+
+ bool OnCooldown = false; ///<
+ uint32 MaxCooldown = 0; ///< Max. cooldown until next free character restoration. Displayed in undelete confirm message. (in sec)
+ uint32 CurrentCooldown = 0; ///< Current cooldown until next free character restoration. (in sec)
+ };
+
class PlayerLogin final : public ClientPacket
{
public:
diff --git a/src/server/game/Server/Packets/SystemPackets.cpp b/src/server/game/Server/Packets/SystemPackets.cpp
new file mode 100644
index 00000000000..c1d11db9ef9
--- /dev/null
+++ b/src/server/game/Server/Packets/SystemPackets.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <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 "SystemPackets.h"
+
+WorldPackets::System::FeatureSystemStatusGlueScreen::FeatureSystemStatusGlueScreen()
+ : ServerPacket(SMSG_FEATURE_SYSTEM_STATUS_GLUE_SCREEN, 1) { }
+
+void WorldPackets::System::FeatureSystemStatusGlueScreen::Write()
+{
+ _worldPacket.WriteBit(BpayStoreEnabled);
+ _worldPacket.WriteBit(BpayStoreAvailable);
+ _worldPacket.WriteBit(BpayStoreDisabledByParentalControls);
+ _worldPacket.WriteBit(CharUndeleteEnabled);
+ _worldPacket.FlushBits();
+}
+
+WorldPackets::System::SetTimeZoneInformation::SetTimeZoneInformation()
+ : ServerPacket(SMSG_SET_TIME_ZONE_INFORMATION) { }
+
+void WorldPackets::System::SetTimeZoneInformation::Write()
+{
+ _worldPacket.reserve(1 + ServerTimeTZ.length() + GameTimeTZ.length());
+
+ _worldPacket.WriteBits(ServerTimeTZ.length(), 7);
+ _worldPacket.WriteBits(GameTimeTZ.length(), 7);
+ _worldPacket.WriteString(ServerTimeTZ);
+ _worldPacket.WriteString(GameTimeTZ);
+}
diff --git a/src/server/game/Server/Packets/SystemPackets.h b/src/server/game/Server/Packets/SystemPackets.h
new file mode 100644
index 00000000000..cb5a22a9b98
--- /dev/null
+++ b/src/server/game/Server/Packets/SystemPackets.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <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 SystemPackets_h__
+#define SystemPackets_h__
+
+#include "Packet.h"
+
+namespace WorldPackets
+{
+ namespace System
+ {
+ class FeatureSystemStatusGlueScreen final : public ServerPacket
+ {
+ public:
+ FeatureSystemStatusGlueScreen();
+
+ void Write() override;
+
+ bool BpayStoreAvailable = false; // NYI
+ bool BpayStoreDisabledByParentalControls = false; // NYI
+ bool CharUndeleteEnabled = false; // NYI
+ bool BpayStoreEnabled = false; // NYI
+ };
+
+ class SetTimeZoneInformation final : public ServerPacket
+ {
+ public:
+ SetTimeZoneInformation();
+
+ void Write() override;
+
+ std::string ServerTimeTZ;
+ std::string GameTimeTZ;
+ };
+ }
+}
+
+#endif // SystemPackets_h__
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 4d62b83552f..12dc1fd096c 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -214,13 +214,14 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_UNSILENCE_VOICE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_VOICE_OFF, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelVoiceOnOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_VOICE_ON, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelVoiceOnOpcode );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_CREATE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCreateOpcode );
+ DEFINE_HANDLER(CMSG_CHAR_CREATE, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharacterCreate, &WorldSession::HandleCharCreateOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_CUSTOMIZE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCustomize );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_DELETE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharDeleteOpcode );
+ DEFINE_HANDLER(CMSG_CHAR_DELETE, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharacterDelete, &WorldSession::HandleCharDeleteOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_ENUM, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharEnumOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_FACTION_CHANGE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_RACE_CHANGE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_RENAME, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharRenameOpcode );
+ DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAR_UNDELETE_ENUM, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharUndeleteEnumOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_FILTERED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_IGNORED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChatIgnoredOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CLEAR_CHANNEL_WATCH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -259,6 +260,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_EQUIPMENT_SET_DELETE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetDelete );
DEFINE_OPCODE_HANDLER_OLD(CMSG_EQUIPMENT_SET_SAVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetSave );
DEFINE_OPCODE_HANDLER_OLD(CMSG_EQUIPMENT_SET_USE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetUse );
+ DEFINE_OPCODE_HANDLER_OLD(CMSG_FACTION_BONUS_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_FAR_SIGHT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleFarSightOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_FORCE_MOVE_ROOT_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck );
DEFINE_OPCODE_HANDLER_OLD(CMSG_FORCE_MOVE_UNROOT_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveUnRootAck );
@@ -585,6 +587,8 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_TUTORIAL_FLAG, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag );
DEFINE_OPCODE_HANDLER_OLD(CMSG_TUTORIAL_RESET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialReset );
DEFINE_OPCODE_HANDLER_OLD(CMSG_UNACCEPT_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode );
+ DEFINE_HANDLER(CMSG_UNDELETE_CHARACTER, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::UndeleteCharacter, &WorldSession::HandleCharUndeleteOpcode);
+ DEFINE_OPCODE_HANDLER_OLD(CMSG_UNDELETE_COOLDOWN_STATUS_QUERY, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleUndeleteCooldownStatusQuery);
DEFINE_OPCODE_HANDLER_OLD(CMSG_UNLEARN_SKILL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnlearnSkillOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_UNLEARN_SPECIALIZATION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnregisterAddonPrefixesOpcode);
@@ -736,6 +740,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_INFO_THROTTLED, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_JOINED, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_LEFT, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDER_CONFIRM, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDPOINTUPDATE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDZONEREPLY, STATUS_UNHANDLED);
@@ -774,7 +779,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_LOGIN_FAILED, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CREATE, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_UNHANDLED);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_DELETE, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_DELETE, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_ENUM, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_FACTION_CHANGE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_RENAME, STATUS_UNHANDLED);
@@ -856,7 +861,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPLORATION_EXPERIENCE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_FAILED_PLAYER_CONDITION, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS, STATUS_UNHANDLED);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS_GLUE_SCREEN, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS_GLUE_SCREEN, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEIGN_DEATH_RESISTED, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_ESCAPED, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_NOT_HOOKED, STATUS_UNHANDLED);
@@ -954,6 +959,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_INFO, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_NOTIFY, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIALIZE_FACTIONS, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIAL_SETUP, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIAL_SPELLS, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INIT_CURRENCY, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INIT_WORLD_STATES, STATUS_UNHANDLED);
@@ -1231,6 +1237,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROJECTILE_POSITION, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_TIME_ZONE_INFORMATION, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOWTAXINODES, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_BANK, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_MAILBOX, STATUS_UNHANDLED);
@@ -1324,6 +1331,8 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_MOVIE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TURN_IN_PETITION_RESULTS, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TUTORIAL_FLAGS, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNDELETE_CHARACTER_RESPONSE, STATUS_NEVER);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNDELETE_COOLDOWN_STATUS_RESPONSE, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNIT_HEALTH_FREQUENT, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNIT_SPELLCAST_START, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA, STATUS_UNHANDLED);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index c08a9409016..7155bd7970b 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -46,7 +46,7 @@ enum OpcodeClient : uint32
CMSG_ADD_IGNORE = 0xBADD,
CMSG_ADD_VOICE_IGNORE = 0xBADD,
CMSG_ALTER_APPEARANCE = 0xBADD,
- CMSG_AREATRIGGER = 0xBADD,
+ CMSG_AREATRIGGER = 0x01B4,
CMSG_AREA_SPIRIT_HEALER_QUERY = 0xBADD,
CMSG_AREA_SPIRIT_HEALER_QUEUE = 0xBADD,
CMSG_ARENA_TEAM_ACCEPT = 0xBADD,
@@ -162,6 +162,7 @@ enum OpcodeClient : uint32
CMSG_CHAR_FACTION_CHANGE = 0xBADD,
CMSG_CHAR_RACE_CHANGE = 0xBADD,
CMSG_CHAR_RENAME = 0xBADD,
+ CMSG_CHAR_UNDELETE_ENUM = 0x0F2D,
CMSG_CHAT_FILTERED = 0xBADD,
CMSG_CHAT_IGNORED = 0xBADD,
CMSG_CLEAR_CHANNEL_WATCH = 0xBADD,
@@ -201,6 +202,7 @@ enum OpcodeClient : uint32
CMSG_EQUIPMENT_SET_DELETE = 0xBADD,
CMSG_EQUIPMENT_SET_SAVE = 0x1B54,
CMSG_EQUIPMENT_SET_USE = 0xBADD,
+ CMSG_FACTION_BONUS_INFO = 0x0928,
CMSG_FAR_SIGHT = 0xBADD,
CMSG_FORCE_MOVE_ROOT_ACK = 0xBADD,
CMSG_FORCE_MOVE_UNROOT_ACK = 0xBADD,
@@ -278,7 +280,7 @@ enum OpcodeClient : uint32
CMSG_GUILD_REPLACE_GUILD_MASTER = 0xBADD,
CMSG_GUILD_REQUEST_CHALLENGE_UPDATE = 0xBADD,
CMSG_GUILD_REQUEST_MAX_DAILY_XP = 0xBADD,
- CMSG_GUILD_REQUEST_PARTY_STATE = 0xBADD,
+ CMSG_GUILD_REQUEST_PARTY_STATE = 0x0A8E,
CMSG_GUILD_ROSTER = 0xBADD,
CMSG_GUILD_SET_ACHIEVEMENT_TRACKING = 0xBADD,
CMSG_GUILD_SET_GUILD_MASTER = 0xBADD,
@@ -443,8 +445,8 @@ enum OpcodeClient : uint32
CMSG_QUESTGIVER_QUERY_QUEST = 0x1924,
CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0xBADD,
CMSG_QUESTGIVER_REQUEST_REWARD = 0xBADD,
- CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0xBADD,
- CMSG_QUESTGIVER_STATUS_QUERY = 0xBADD,
+ CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x0131,
+ CMSG_QUESTGIVER_STATUS_QUERY = 0x0704,
CMSG_QUESTLOG_REMOVE_QUEST = 0xBADD,
CMSG_QUESTLOG_SWAP_QUEST = 0xBADD,
CMSG_QUEST_CONFIRM_ACCEPT = 0xBADD,
@@ -458,7 +460,7 @@ enum OpcodeClient : uint32
CMSG_RECLAIM_CORPSE = 0xBADD,
CMSG_REDIRECTION_AUTH_PROOF = 0x0485,
CMSG_REFORGE_ITEM = 0xBADD,
- CMSG_REORDER_CHARACTERS = 0xBADD,
+ CMSG_REORDER_CHARACTERS = 0x0DAA,
CMSG_REPAIR_ITEM = 0xBADD,
CMSG_REPLACE_ACCOUNT_DATA = 0xBADD,
CMSG_REPOP_REQUEST = 0xBADD,
@@ -567,6 +569,8 @@ enum OpcodeClient : uint32
CMSG_TUTORIAL_FLAG = 0xBADD,
CMSG_TUTORIAL_RESET = 0xBADD,
CMSG_UNACCEPT_TRADE = 0xBADD,
+ CMSG_UNDELETE_CHARACTER = 0x0D99,
+ CMSG_UNDELETE_COOLDOWN_STATUS_QUERY = 0x19A9,
CMSG_UNLEARN_SKILL = 0xBADD,
CMSG_UNLEARN_SPECIALIZATION = 0xBADD,
CMSG_UNREGISTER_ALL_ADDON_PREFIXES = 0xBADD,
@@ -738,6 +742,7 @@ enum OpcodeServer : uint32
SMSG_BATTLEGROUND_INFO_THROTTLED = 0xBADD,
SMSG_BATTLEGROUND_PLAYER_JOINED = 0xBADD,
SMSG_BATTLEGROUND_PLAYER_LEFT = 0xBADD,
+ SMSG_BATTLE_PET_JOURNAL = 0x19A2,
SMSG_BINDER_CONFIRM = 0xBADD,
SMSG_BINDPOINTUPDATE = 0x0A30,
SMSG_BINDZONEREPLY = 0xBADD,
@@ -916,7 +921,7 @@ enum OpcodeServer : uint32
SMSG_GROUP_SET_LEADER = 0xBADD,
SMSG_GROUP_SET_ROLE = 0xBADD,
SMSG_GROUP_UNINVITE = 0xBADD,
- SMSG_GUILD_ACHIEVEMENT_DATA = 0xBADD,
+ SMSG_GUILD_ACHIEVEMENT_DATA = 0x1866,
SMSG_GUILD_ACHIEVEMENT_DELETED = 0xBADD,
SMSG_GUILD_ACHIEVEMENT_EARNED = 0xBADD,
SMSG_GUILD_ACHIEVEMENT_MEMBERS = 0xBADD,
@@ -933,7 +938,7 @@ enum OpcodeServer : uint32
SMSG_GUILD_CRITERIA_DATA = 0xBADD,
SMSG_GUILD_CRITERIA_DELETED = 0xBADD,
SMSG_GUILD_DECLINE = 0xBADD,
- SMSG_GUILD_EVENT = 0xBADD,
+ SMSG_GUILD_EVENT = 0x1027,
SMSG_GUILD_EVENT_LOG_QUERY_RESULT = 0xBADD,
SMSG_GUILD_EVENT_PRESENCE_CHANGE = 0x1228,
SMSG_GUILD_FLAGGED_FOR_RENAME = 0xBADD,
@@ -950,12 +955,12 @@ enum OpcodeServer : uint32
SMSG_GUILD_MOVE_STARTING = 0xBADD,
SMSG_GUILD_NEWS_DELETED = 0xBADD,
SMSG_GUILD_NEWS_UPDATE = 0xBADD,
- SMSG_GUILD_PARTY_STATE_RESPONSE = 0xBADD,
+ SMSG_GUILD_PARTY_STATE_RESPONSE = 0x1225,
SMSG_GUILD_PERMISSIONS_QUERY_RESULTS = 0xBADD,
SMSG_GUILD_QUERY_RESPONSE = 0x1046,
SMSG_GUILD_RANK = 0x1218,
SMSG_GUILD_RANKS_UPDATE = 0xBADD,
- SMSG_GUILD_RECIPES = 0xBADD,
+ SMSG_GUILD_RECIPES = 0x1078,
SMSG_GUILD_RENAMED = 0xBADD,
SMSG_GUILD_REPUTATION_REACTION_CHANGED = 0xBADD,
SMSG_GUILD_REPUTATION_WEEKLY_CAP = 0xBADD,
@@ -974,7 +979,8 @@ enum OpcodeServer : uint32
SMSG_HOTFIX_NOTIFY = 0xBADD,
SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0xBADD,
SMSG_IGNORE_REQUIREMENTS_CHEAT = 0xBADD,
- SMSG_INITIALIZE_FACTIONS = 0xBADD,
+ SMSG_INITIALIZE_FACTIONS = 0x0B10,
+ SMSG_INITIAL_SETUP = 0x0B07,
SMSG_INITIAL_SPELLS = 0x0A81,
SMSG_INIT_CURRENCY = 0x0B06,
SMSG_INIT_WORLD_STATES = 0x0B04,
@@ -1013,7 +1019,7 @@ enum OpcodeServer : uint32
SMSG_LFG_OFFER_CONTINUE = 0xBADD,
SMSG_LFG_OPEN_FROM_GOSSIP = 0xBADD,
SMSG_LFG_PARTY_INFO = 0xBADD,
- SMSG_LFG_PLAYER_INFO = 0xBADD,
+ SMSG_LFG_PLAYER_INFO = 0x0F36,
SMSG_LFG_PLAYER_REWARD = 0xBADD,
SMSG_LFG_PROPOSAL_UPDATE = 0xBADD,
SMSG_LFG_QUEUE_STATUS = 0xBADD,
@@ -1139,7 +1145,7 @@ enum OpcodeServer : uint32
SMSG_PARTY_MEMBER_STATS = 0xBADD,
SMSG_PARTY_MEMBER_STATS_FULL = 0xBADD,
SMSG_PAUSE_MIRROR_TIMER = 0xBADD,
- SMSG_PERIODICAURALOG = 0xBADD,
+ SMSG_PERIODICAURALOG = 0x0B1B,
SMSG_PETGODMODE = 0xBADD,
SMSG_PETITION_ALREADY_SIGNED = 0xBADD,
SMSG_PETITION_QUERY_RESPONSE = 0xBADD,
@@ -1179,7 +1185,7 @@ enum OpcodeServer : uint32
SMSG_PLAY_SPELL_VISUAL_KIT = 0xBADD,
SMSG_PLAY_TIME_WARNING = 0xBADD,
SMSG_PONG = 0x17CA,
- SMSG_POWER_UPDATE = 0xBADD,
+ SMSG_POWER_UPDATE = 0x0B27,
SMSG_PRE_RESURRECT = 0xBADD,
SMSG_PROCRESIST = 0xBADD,
SMSG_PROPOSE_LEVEL_GRANT = 0xBADD,
@@ -1196,8 +1202,8 @@ enum OpcodeServer : uint32
SMSG_QUESTGIVER_QUEST_INVALID = 0xBADD,
SMSG_QUESTGIVER_QUEST_LIST = 0xBADD,
SMSG_QUESTGIVER_REQUEST_ITEMS = 0xBADD,
- SMSG_QUESTGIVER_STATUS = 0xBADD,
- SMSG_QUESTGIVER_STATUS_MULTIPLE = 0xBADD,
+ SMSG_QUESTGIVER_STATUS = 0x1567,
+ SMSG_QUESTGIVER_STATUS_MULTIPLE = 0x17C6,
SMSG_QUESTLOG_FULL = 0xBADD,
SMSG_QUESTUPDATE_ADD_ITEM = 0xBADD,
SMSG_QUESTUPDATE_ADD_KILL = 0xBADD,
@@ -1205,7 +1211,7 @@ enum OpcodeServer : uint32
SMSG_QUESTUPDATE_COMPLETE = 0xBADD,
SMSG_QUESTUPDATE_FAILED = 0xBADD,
SMSG_QUESTUPDATE_FAILEDTIMER = 0xBADD,
- SMSG_QUEST_NPC_QUERY_RESPONSE = 0xBADD,
+ SMSG_QUEST_NPC_QUERY_RESPONSE = 0x1591,
SMSG_QUEST_CONFIRM_ACCEPT = 0xBADD,
SMSG_QUEST_FORCE_REMOVE = 0xBADD,
SMSG_QUEST_POI_QUERY_RESPONSE = 0x1715,
@@ -1245,7 +1251,6 @@ enum OpcodeServer : uint32
SMSG_RWHOIS = 0xBADD,
SMSG_SELL_ITEM = 0xBADD,
SMSG_SEND_MAIL_RESULT = 0x0302,
- SMSG_SEND_SERVER_LOCATION = 0x153E,
SMSG_SEND_UNLEARN_SPELLS = 0x1A82,
SMSG_SERVERTIME = 0xBADD,
SMSG_SERVER_FIRST_ACHIEVEMENT = 0xBADD,
@@ -1268,6 +1273,7 @@ enum OpcodeServer : uint32
SMSG_SET_PLAY_HOVER_ANIM = 0xBADD,
SMSG_SET_PROFICIENCY = 0x00D3,
SMSG_SET_PROJECTILE_POSITION = 0xBADD,
+ SMSG_SET_TIME_ZONE_INFORMATION = 0x153E,
SMSG_SET_VIGNETTE = 0x09AC,
SMSG_SHOWTAXINODES = 0xBADD,
SMSG_SHOW_BANK = 0x0204,
@@ -1278,11 +1284,11 @@ enum OpcodeServer : uint32
SMSG_SPELLBREAKLOG = 0xBADD,
SMSG_SPELLDAMAGESHIELD = 0xBADD,
SMSG_SPELLDISPELLOG = 0xBADD,
- SMSG_SPELLENERGIZELOG = 0xBADD,
- SMSG_SPELLHEALLOG = 0xBADD,
+ SMSG_SPELLENERGIZELOG = 0x137C,
+ SMSG_SPELLHEALLOG = 0x0114,
SMSG_SPELLINSTAKILLLOG = 0xBADD,
SMSG_SPELLINTERRUPTLOG = 0xBADD,
- SMSG_SPELLLOGEXECUTE = 0xBADD,
+ SMSG_SPELLLOGEXECUTE = 0x1823,
SMSG_SPELLLOGMISS = 0xBADD,
SMSG_SPELLNONMELEEDAMAGELOG = 0x11FB,
SMSG_SPELLORDAMAGE_IMMUNE = 0xBADD,
@@ -1358,14 +1364,16 @@ enum OpcodeServer : uint32
SMSG_TRAINER_BUY_SUCCEEDED = 0xBADD,
SMSG_TRAINER_LIST = 0x0BA9,
SMSG_TRANSFER_ABORTED = 0xBADD,
- SMSG_TRANSFER_PENDING = 0xBADD,
+ SMSG_TRANSFER_PENDING = 0x172A,
SMSG_TRIGGER_CINEMATIC = 0xBADD,
SMSG_TRIGGER_MOVIE = 0xBADD,
SMSG_TURN_IN_PETITION_RESULTS = 0xBADD,
SMSG_TUTORIAL_FLAGS = 0x020F,
+ SMSG_UNDELETE_CHARACTER_RESPONSE = 0x0344,
+ SMSG_UNDELETE_COOLDOWN_STATUS_RESPONSE = 0x0310,
SMSG_UNIT_HEALTH_FREQUENT = 0xBADD,
SMSG_UNIT_SPELLCAST_START = 0xBADD,
- SMSG_UPDATE_ACCOUNT_DATA = 0xBADD,
+ SMSG_UPDATE_ACCOUNT_DATA = 0x1520,
SMSG_UPDATE_ACCOUNT_DATA_COMPLETE = 0xBADD,
SMSG_UPDATE_COMBO_POINTS = 0xBADD,
SMSG_UPDATE_CURRENCY = 0xBADD,
diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h
index d04679adbd4..e7d6d4fb5b1 100644
--- a/src/server/game/Server/WorldPacket.h
+++ b/src/server/game/Server/WorldPacket.h
@@ -23,8 +23,6 @@
#include "Opcodes.h"
#include "ByteBuffer.h"
-struct z_stream_s;
-
class WorldPacket : public ByteBuffer
{
public:
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 1bc2dc7cc82..ac25da2d559 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -21,7 +21,6 @@
*/
#include "WorldSocket.h"
-#include "Packet.h"
#include <zlib.h>
#include "Config.h"
#include "Common.h"
@@ -49,6 +48,7 @@
#include "WardenWin.h"
#include "WardenMac.h"
#include "BattlenetServerManager.h"
+#include "CharacterPackets.h"
namespace {
@@ -1042,25 +1042,32 @@ void WorldSession::SetPlayer(Player* player)
void WorldSession::InitializeQueryCallbackParameters()
{
// Callback parameters that have pointers in them should be properly
- // initialized to NULL here.
- _charCreateCallback.SetParam(NULL);
+ // initialized to nullptr here.
+ _charRenameCallback.SetParam(nullptr);
}
void WorldSession::ProcessQueryCallbacks()
{
PreparedQueryResult result;
- //! HandleCharEnumOpcode
- if (_charEnumCallback.valid() && _charEnumCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
+ //! HandleCharEnumOpcode and HandleCharUndeleteEnumOpcode
+ if (_charEnumCallback.IsReady())
{
- result = _charEnumCallback.get();
- HandleCharEnum(result);
+ _charEnumCallback.GetResult(result);
+
+ if (bool undelete = _charEnumCallback.GetParam())
+ HandleCharUndeleteEnum(result);
+ else
+ HandleCharEnum(result);
+
+ _charEnumCallback.FreeResult();
}
+ //! HandleCharCreateOpcode
if (_charCreateCallback.IsReady())
{
_charCreateCallback.GetResult(result);
- HandleCharCreateCallback(result, _charCreateCallback.GetParam());
+ HandleCharCreateCallback(result, _charCreateCallback.GetParam().get());
}
//! HandlePlayerLoginOpcode
@@ -1083,12 +1090,27 @@ void WorldSession::ProcessQueryCallbacks()
if (_charRenameCallback.IsReady())
{
_charRenameCallback.GetResult(result);
- CharacterRenameInfo* renameInfo = _charRenameCallback.GetParam();
- HandleChangePlayerNameOpcodeCallBack(result, renameInfo);
+ WorldPackets::Character::CharacterRenameInfo* renameInfo = _charRenameCallback.GetParam();
+ HandleCharRenameCallBack(result, renameInfo);
delete renameInfo;
_charRenameCallback.Reset();
}
+ /// HandleUndeleteCooldownStatusOpcode
+ /// wait until no char undelete is in progress
+ if (!_charUndeleteCallback.GetStage() && _undeleteCooldownStatusCallback.IsReady())
+ {
+ _undeleteCooldownStatusCallback.GetResult(result);
+ HandleUndeleteCooldownStatusCallback(result);
+ }
+
+ /// HandleCharUndeleteOpcode
+ if (_charUndeleteCallback.IsReady())
+ {
+ _charUndeleteCallback.GetResult(result);
+ HandleCharUndeleteCallback(result, _charUndeleteCallback.GetParam().get());
+ }
+
//- HandleCharAddIgnoreOpcode
if (_addIgnoreCallback.valid() && _addIgnoreCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index f195bf2908d..6ab85070925 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -54,6 +54,7 @@ struct DeclinedName;
struct ItemTemplate;
struct MovementInfo;
struct TradeStatusInfo;
+struct z_stream_s;
namespace lfg
{
@@ -73,10 +74,17 @@ class RBACData;
namespace WorldPackets
{
- class ServerPacket;
-
namespace Character
{
+ struct CharacterCreateInfo;
+ struct CharacterRenameInfo;
+ struct CharacterCustomizeInfo;
+ struct CharacterFactionChangeInfo;
+ struct CharacterUndeleteInfo;
+
+ class CharacterCreate;
+ class CharacterDelete;
+ class UndeleteCharacter;
class PlayerLogin;
}
}
@@ -176,6 +184,7 @@ private:
PacketFilter(PacketFilter const& right) = delete;
PacketFilter& operator=(PacketFilter const& right) = delete;
};
+
//process only thread-safe packets in Map::Update()
class MapSessionFilter : public PacketFilter
{
@@ -199,62 +208,6 @@ public:
virtual bool Process(WorldPacket* packet) override;
};
-// Proxy structure to contain data passed to callback function,
-// only to prevent bloating the parameter list
-class CharacterCreateInfo
-{
- friend class WorldSession;
- friend class Player;
-
- protected:
- /// User specified variables
- std::string Name;
- uint8 Race = 0;
- uint8 Class = 0;
- uint8 Gender = GENDER_NONE;
- uint8 Skin = 0;
- uint8 Face = 0;
- uint8 HairStyle = 0;
- uint8 HairColor = 0;
- uint8 FacialHair = 0;
- uint8 OutfitId = 0;
-
- /// Server side data
- uint8 CharCount = 0;
-};
-
-struct CharacterRenameInfo
-{
- friend class WorldSession;
-
- protected:
- ObjectGuid Guid;
- std::string Name;
-};
-
-struct CharacterCustomizeInfo : public CharacterRenameInfo
-{
- friend class Player;
- friend class WorldSession;
-
- protected:
- uint8 Gender = GENDER_NONE;
- uint8 Skin = 0;
- uint8 Face = 0;
- uint8 HairStyle = 0;
- uint8 HairColor = 0;
- uint8 FacialHair = 0;
-};
-
-struct CharacterFactionChangeInfo : public CharacterCustomizeInfo
-{
- friend class Player;
- friend class WorldSession;
-
- protected:
- uint8 Race = 0;
-};
-
struct PacketCounter
{
time_t lastReceiveTime;
@@ -337,6 +290,9 @@ class WorldSession
/// Handle the authentication waiting queue (to be completed)
void SendAuthWaitQue(uint32 position);
+ void SendSetTimeZoneInformation();
+ void SendFeatureSystemStatusGlueScreen();
+
void SendNameQueryOpcode(ObjectGuid guid);
void SendTrainerList(ObjectGuid guid);
@@ -471,25 +427,38 @@ class WorldSession
void Handle_ServerSide(WorldPacket& recvPacket); // sever side only, can't be accepted from client
void Handle_Deprecated(WorldPacket& recvPacket); // never used anymore by client
- void HandleCharEnumOpcode(WorldPacket& recvPacket);
- void HandleCharDeleteOpcode(WorldPacket& recvPacket);
- void HandleCharCreateOpcode(WorldPacket& recvPacket);
- void HandleCharCreateCallback(PreparedQueryResult result, CharacterCreateInfo* createInfo);
+ void HandleCharEnum(PreparedQueryResult result);
+ void HandleCharEnumOpcode(WorldPacket& /*recvData*/);
+ void HandleCharUndeleteEnum(PreparedQueryResult result);
+ void HandleCharUndeleteEnumOpcode(WorldPacket& /*recvData*/);
+ void HandleCharDeleteOpcode(WorldPackets::Character::CharacterDelete& charDelete);
+ void HandleCharCreateOpcode(WorldPackets::Character::CharacterCreate& charCreate);
+ void HandleCharCreateCallback(PreparedQueryResult result, WorldPackets::Character::CharacterCreateInfo* createInfo);
void HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& playerLogin);
void HandleLoadScreenOpcode(WorldPacket& recvPacket);
- void HandleCharEnum(PreparedQueryResult result);
void HandlePlayerLogin(LoginQueryHolder * holder);
+ void HandleCharRenameOpcode(WorldPacket& recvData);
+ void HandleCharRenameCallBack(PreparedQueryResult result, WorldPackets::Character::CharacterRenameInfo const* renameInfo);
+ void HandleSetPlayerDeclinedNames(WorldPacket& recvData);
+ void HandleAlterAppearance(WorldPacket& recvData);
void HandleCharFactionOrRaceChange(WorldPacket& recvData);
void HandleRandomizeCharNameOpcode(WorldPacket& recvData);
void HandleReorderCharacters(WorldPacket& recvData);
void HandleOpeningCinematic(WorldPacket& recvData);
+ void HandleUndeleteCooldownStatusQuery(WorldPacket& /*recvData*/);
+ void HandleUndeleteCooldownStatusCallback(PreparedQueryResult result);
+ void HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCharacter& undeleteInfo);
+ void HandleCharUndeleteCallback(PreparedQueryResult result, WorldPackets::Character::CharacterUndeleteInfo* undeleteInfo);
+
void SendCharCreate(ResponseCodes result);
void SendCharDelete(ResponseCodes result);
- void SendCharRename(ResponseCodes result, CharacterRenameInfo const& renameInfo);
- void SendCharCustomize(ResponseCodes result, CharacterCustomizeInfo const& customizeInfo);
- void SendCharFactionChange(ResponseCodes result, CharacterFactionChangeInfo const& factionChangeInfo);
+ void SendCharRename(ResponseCodes result, WorldPackets::Character::CharacterRenameInfo const& renameInfo);
+ void SendCharCustomize(ResponseCodes result, WorldPackets::Character::CharacterCustomizeInfo const& customizeInfo);
+ void SendCharFactionChange(ResponseCodes result, WorldPackets::Character::CharacterFactionChangeInfo const& factionChangeInfo);
void SendSetPlayerDeclinedNamesResult(DeclinedNameResult result, ObjectGuid guid);
void SendBarberShopResult(BarberShopResult result);
+ void SendUndeleteCooldownStatusResponse(uint32 currentCooldown, uint32 maxCooldown);
+ void SendUndeleteCharacterResponse(CharacterUndeleteResult result, WorldPackets::Character::CharacterUndeleteInfo const* undeleteInfo);
// played time
void HandlePlayedTime(WorldPacket& recvPacket);
@@ -858,10 +827,6 @@ class WorldSession
void HandleSetActionBarToggles(WorldPacket& recvData);
- void HandleCharRenameOpcode(WorldPacket& recvData);
- void HandleChangePlayerNameOpcodeCallBack(PreparedQueryResult result, CharacterRenameInfo const* renameInfo);
- void HandleSetPlayerDeclinedNames(WorldPacket& recvData);
-
void HandleTotemDestroyed(WorldPacket& recvData);
void HandleDismissCritter(WorldPacket& recvData);
@@ -1026,7 +991,6 @@ class WorldSession
// Miscellaneous
void HandleSpellClick(WorldPacket& recvData);
void HandleMirrorImageDataRequest(WorldPacket& recvData);
- void HandleAlterAppearance(WorldPacket& recvData);
void HandleRemoveGlyph(WorldPacket& recvData);
void HandleCharCustomize(WorldPacket& recvData);
void HandleQueryInspectAchievements(WorldPacket& recvData);
@@ -1057,15 +1021,17 @@ class WorldSession
void InitializeQueryCallbackParameters();
void ProcessQueryCallbacks();
- PreparedQueryResultFuture _charEnumCallback;
PreparedQueryResultFuture _addIgnoreCallback;
PreparedQueryResultFuture _stablePetCallback;
- QueryCallback<PreparedQueryResult, CharacterRenameInfo*> _charRenameCallback;
+ QueryCallback<PreparedQueryResult, bool> _charEnumCallback;
QueryCallback<PreparedQueryResult, std::string> _addFriendCallback;
QueryCallback<PreparedQueryResult, uint32> _unstablePetCallback;
QueryCallback<PreparedQueryResult, uint32> _stableSwapCallback;
QueryCallback<PreparedQueryResult, ObjectGuid> _sendStabledPetCallback;
- QueryCallback<PreparedQueryResult, CharacterCreateInfo*, true> _charCreateCallback;
+ QueryCallback<PreparedQueryResult, std::shared_ptr<WorldPackets::Character::CharacterCreateInfo>, true> _charCreateCallback;
+ QueryCallback<PreparedQueryResult, WorldPackets::Character::CharacterRenameInfo*> _charRenameCallback;
+ QueryCallback<PreparedQueryResult, bool, true> _undeleteCooldownStatusCallback;
+ QueryCallback<PreparedQueryResult, std::shared_ptr<WorldPackets::Character::CharacterUndeleteInfo>, true> _charUndeleteCallback;
QueryResultHolderFuture _charLoginCallback;
friend class World;
diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp
index 556913c60a6..79d96200d80 100644
--- a/src/server/game/Tools/PlayerDump.cpp
+++ b/src/server/game/Tools/PlayerDump.cpp
@@ -389,7 +389,7 @@ void fixNULLfields(std::string &line)
DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, std::string name, ObjectGuid::LowType guid)
{
uint32 charcount = AccountMgr::GetCharactersCount(account);
- if (charcount >= 10)
+ if (charcount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
return DUMP_TOO_MANY_CHARS;
FILE* fin = fopen(file.c_str(), "r");
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 7e3f8351dbc..875bf2bba19 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -271,6 +271,10 @@ void World::AddSession_(WorldSession* s)
}
s->SendAuthResponse(AUTH_OK, false);
+
+ s->SendSetTimeZoneInformation();
+ s->SendFeatureSystemStatusGlueScreen();
+
s->SendAddonsInfo();
s->SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION));
s->SendTutorialsData();
@@ -707,11 +711,11 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK] = sConfigMgr->GetIntDefault("CharacterCreating.Disabled.RaceMask", 0);
m_int_configs[CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK] = sConfigMgr->GetIntDefault("CharacterCreating.Disabled.ClassMask", 0);
- m_int_configs[CONFIG_CHARACTERS_PER_REALM] = sConfigMgr->GetIntDefault("CharactersPerRealm", 10);
- if (m_int_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_int_configs[CONFIG_CHARACTERS_PER_REALM] > 10)
+ m_int_configs[CONFIG_CHARACTERS_PER_REALM] = sConfigMgr->GetIntDefault("CharactersPerRealm", MAX_CHARACTERS_PER_REALM);
+ if (m_int_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_int_configs[CONFIG_CHARACTERS_PER_REALM] > MAX_CHARACTERS_PER_REALM)
{
TC_LOG_ERROR("server.loading", "CharactersPerRealm (%i) must be in range 1..10. Set to 10.", m_int_configs[CONFIG_CHARACTERS_PER_REALM]);
- m_int_configs[CONFIG_CHARACTERS_PER_REALM] = 10;
+ m_int_configs[CONFIG_CHARACTERS_PER_REALM] = MAX_CHARACTERS_PER_REALM;
}
// must be after CONFIG_CHARACTERS_PER_REALM
@@ -1226,6 +1230,11 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_WARDEN_CLIENT_FAIL_ACTION] = sConfigMgr->GetIntDefault("Warden.ClientCheckFailAction", 0);
m_int_configs[CONFIG_WARDEN_CLIENT_RESPONSE_DELAY] = sConfigMgr->GetIntDefault("Warden.ClientResponseDelay", 600);
+ // Feature System
+ m_bool_configs[CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED] = sConfigMgr->GetBoolDefault("FeatureSystem.BpayStore.Enabled", false);
+ m_bool_configs[CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED] = sConfigMgr->GetBoolDefault("FeatureSystem.CharacterUndelete.Enabled", false);
+ m_int_configs[CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN] = sConfigMgr->GetIntDefault("FeatureSystem.CharacterUndelete.Cooldown", 2592000);
+
// Dungeon finder
m_int_configs[CONFIG_LFG_OPTIONSMASK] = sConfigMgr->GetIntDefault("DungeonFinder.OptionsMask", 1);
@@ -3190,7 +3199,7 @@ void World::ProcessQueryCallbacks()
{
PreparedQueryResult result;
- for (std::deque<std::future<PreparedQueryResult>>::iterator itr = m_realmCharCallbacks.begin(); itr != m_realmCharCallbacks.end(); )
+ for (std::deque<PreparedQueryResultFuture>::iterator itr = m_realmCharCallbacks.begin(); itr != m_realmCharCallbacks.end(); )
{
if ((*itr).wait_for(std::chrono::seconds(0)) != std::future_status::ready)
{
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index ae07a5434f1..4f4c3451b02 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -170,6 +170,8 @@ enum WorldBoolConfigs
CONFIG_ALLOW_TRACK_BOTH_RESOURCES,
CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA,
CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA,
+ CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED,
+ CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED,
BOOL_CONFIG_VALUE_COUNT
};
@@ -358,6 +360,7 @@ enum WorldIntConfigs
CONFIG_BG_REWARD_WINNER_CONQUEST_LAST,
CONFIG_CREATURE_PICKPOCKET_REFILL,
CONFIG_AHBOT_UPDATE_INTERVAL,
+ CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN,
INT_CONFIG_VALUE_COUNT
};
@@ -510,6 +513,8 @@ enum WorldStates
WS_GUILD_WEEKLY_RESET_TIME = 20050, // Next guild week reset time
};
+#define MAX_CHARACTERS_PER_REALM 11
+
/// Storage class for commands issued for delayed execution
struct CliCommandHolder
{
@@ -878,7 +883,7 @@ class World
void LoadCharacterNameData();
void ProcessQueryCallbacks();
- std::deque<std::future<PreparedQueryResult>> m_realmCharCallbacks;
+ std::deque<PreparedQueryResultFuture> m_realmCharCallbacks;
};
extern Battlenet::RealmHandle realmHandle;
diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp
index cfde57f3184..0b351e310f4 100644
--- a/src/server/scripts/Commands/cs_character.cpp
+++ b/src/server/scripts/Commands/cs_character.cpp
@@ -105,7 +105,7 @@ public:
if (isNumeric(searchString.c_str()))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID);
- stmt->setUInt64(0, uint32(atoi(searchString.c_str())));
+ stmt->setUInt64(0, strtoull(searchString.c_str(), nullptr, 10));
result = CharacterDatabase.Query(stmt);
}
// search by name
@@ -205,7 +205,7 @@ public:
// check character count
uint32 charcount = AccountMgr::GetCharactersCount(delInfo.accountId);
- if (charcount >= 10)
+ if (charcount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
{
handler->PSendSysMessage(LANG_CHARACTER_DELETED_SKIP_FULL, delInfo.name.c_str(), delInfo.guid.ToString().c_str(), delInfo.accountId);
return;
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 8abf6571af2..796b5d27a1e 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -51,12 +51,21 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"cb.guid, c.slot, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? "
"LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
"LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_UNDELETE_ENUM, "SELECT c.guid, c.deleteInfos_Name, c.race, c.class, c.gender, c.playerBytes, c.playerBytes2, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, "
+ "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.slot "
+ "FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
+ "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.deleteInfos_Account = ? AND c.deleteInfos_Name IS NOT NULL", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME, "SELECT c.guid, c.deleteInfos_Name, c.race, c.class, c.gender, c.playerBytes, c.playerBytes2, c.level, c.zone, c.map, "
+ "c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, "
+ "cb.guid, c.slot, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? "
+ "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
+ "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.deleteInfos_Account = ? AND c.deleteInfos_Name IS NOT NULL", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_FREE_NAME, "SELECT name FROM characters WHERE guid = ? AND account = ? AND (at_login & ?) = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME, "SELECT guid, race, account FROM characters WHERE name = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_CHAR_RACE, "SELECT race FROM characters WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_LEVEL, "SELECT level FROM characters WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_ZONE, "SELECT zone FROM characters WHERE guid = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_CHARACTER_NAME_DATA, "SELECT race, class, gender, level FROM characters WHERE guid = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_CHARACTER_NAME_DATA, "SELECT race, class, gender, level FROM characters WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?", CONNECTION_SYNCH);
@@ -432,7 +441,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_CHARACTER_POSITION, "UPDATE characters SET position_x = ?, position_y = ?, position_z = ?, orientation = ?, map = ?, zone = ?, trans_x = 0, trans_y = 0, trans_z = 0, transguid = 0, taxi_path = '' WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name, character_aura.remaintime FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHARACTER_ONLINE, "SELECT name, account, map, zone FROM characters WHERE online > 0", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT guid FROM characters WHERE account = ?", CONNECTION_SYNCH);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index 1a1b2f56669..329f2a5c23d 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -63,6 +63,8 @@ enum CharacterDatabaseStatements
CHAR_SEL_MAIL_LIST_ITEMS,
CHAR_SEL_ENUM,
CHAR_SEL_ENUM_DECLINED_NAME,
+ CHAR_SEL_UNDELETE_ENUM,
+ CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME,
CHAR_SEL_FREE_NAME,
CHAR_SEL_GUID_RACE_ACC_BY_NAME,
CHAR_SEL_CHAR_RACE,
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index 75915a4eeaf..c0c9751a804 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -136,4 +136,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK, "UPDATE battlenet_accounts SET locked = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY, "UPDATE battlenet_accounts SET lock_country = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, "SELECT battlenet_account FROM account WHERE id = ?", CONNECTION_SYNCH);
+
+ PrepareStatement(LOGIN_SEL_LAST_CHAR_UNDELETE, "SELECT LastCharacterUndelete FROM battlenet_accounts WHERE Id = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_LAST_CHAR_UNDELETE, "UPDATE battlenet_accounts SET LastCharacterUndelete = UNIX_TIMESTAMP() WHERE Id = ?", CONNECTION_ASYNC);
}
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h
index 78d5c55559f..bf4b8511e67 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.h
+++ b/src/server/shared/Database/Implementation/LoginDatabase.h
@@ -153,6 +153,9 @@ enum LoginDatabaseStatements
LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY,
LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT,
+ LOGIN_SEL_LAST_CHAR_UNDELETE,
+ LOGIN_UPD_LAST_CHAR_UNDELETE,
+
MAX_LOGINDATABASE_STATEMENTS
};
diff --git a/src/server/shared/Threading/Callback.h b/src/server/shared/Threading/Callback.h
index b462fce25d5..03073d4a792 100644
--- a/src/server/shared/Threading/Callback.h
+++ b/src/server/shared/Threading/Callback.h
@@ -45,7 +45,7 @@ class QueryCallback
return _result;
}
- int IsReady()
+ bool IsReady()
{
return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
@@ -128,7 +128,7 @@ class QueryCallback_2
return _result;
}
- int IsReady()
+ bool IsReady()
{
return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index e2d8cd3a195..216fe08d64a 100644
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -30,9 +30,11 @@
template<typename T>
struct Optional
-{
- T value;
- bool HasValue;
+{
+ Optional() : value(), HasValue(false) { }
+
+ T value;
+ bool HasValue;
};
// Searcher for map of structs
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index a927e45e89e..4d40365451e 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1074,10 +1074,31 @@ Account.PasswordChangeSecurity = 0
# Description: Set to date of project's birth in UNIX time. By default the date when
# TrinityCore was started (Thu Oct 2, 2008)
# Default: 1222964635
+
+BirthdayTime = 1222964635
+
+#
+# FeatureSystem.BpayStore.Enabled
+# Description: Not yet implemented
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+FeatureSystem.BpayStore.Enabled = 0
+
#
+# FeatureSystem.CharacterUndelete.Enabled
+# Description: Controls Feature in CharacterList to restore delete Characters.
+# Default: 0 - (Disabled)
+# 1 - (Enabled, Experimental)
+
+FeatureSystem.CharacterUndelete.Enabled = 0
+
#
+# FeatureSystem.CharacterUndelete.Cooldown
+# Description: Time between available character restorations. (in sec)
+# Default: 2592000 (30 days)
-BirthdayTime = 1222964635
+FeatureSystem.CharacterUndelete.Cooldown = 2592000
#
###################################################################################################