Merge remote branch 'origin/master' into 330

This commit is contained in:
tomrus88 2009-11-14 13:02:54 +03:00
commit 23bfcccd77
31 changed files with 399 additions and 246 deletions

View file

@ -151,6 +151,26 @@ else
AC_MSG_RESULT($DO_MYSQL) AC_MSG_RESULT($DO_MYSQL)
fi fi
## Check for memory allocator
# Use libc-malloc or libtbb-malloc?
AC_MSG_CHECKING(whether to use libc malloc)
MANGOSD_STD_MALLOC=no
AC_ARG_WITH(std-malloc,
[
Memory allocation options:
--with-std-malloc Use standard malloc],
[
if test "$withval" = "yes" ; then
CFLAGS="-DUSE_STANDARD_MALLOC $CFLAGS"
CXXFLAGS="-DUSE_STANDARD_MALLOC $CXXFLAGS"
MANGOSD_STD_MALLOC=yes
elif test "$withval" != "no" ; then
AC_MSG_ERROR(Please choose yes or no)
fi
])
AC_MSG_RESULT($MANGOSD_STD_MALLOC)
## Check for options ## Check for options
# Include debug info in library? # Include debug info in library?
AC_MSG_CHECKING(whether to include debug info in library) AC_MSG_CHECKING(whether to include debug info in library)

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL, `version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0', `cache_id` int(10) default '0',
`required_8777_02_mangos_gameobject` bit(1) default NULL `required_8803_02_mangos_playercreateinfo_action` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
-- --
@ -10420,7 +10420,7 @@ INSERT INTO `playercreateinfo_action` VALUES
(8,1,72,6603,0), (8,1,72,6603,0),
(8,1,73,78,0), (8,1,73,78,0),
(8,1,74,2764,0), (8,1,74,2764,0),
(8,1,75,26296,0), (8,1,75,26297,0),
(8,1,83,117,128), (8,1,83,117,128),
(8,1,84,6603,0), (8,1,84,6603,0),
(8,1,96,6603,0), (8,1,96,6603,0),
@ -10428,7 +10428,7 @@ INSERT INTO `playercreateinfo_action` VALUES
(8,3,0,6603,0), (8,3,0,6603,0),
(8,3,1,2973,0), (8,3,1,2973,0),
(8,3,2,75,0), (8,3,2,75,0),
(8,3,3,20554,0), (8,3,3,26297,0),
(8,3,10,159,128), (8,3,10,159,128),
(8,3,11,4604,128), (8,3,11,4604,128),
(8,4,0,6603,0), (8,4,0,6603,0),
@ -10440,7 +10440,7 @@ INSERT INTO `playercreateinfo_action` VALUES
(8,5,0,6603,0), (8,5,0,6603,0),
(8,5,1,585,0), (8,5,1,585,0),
(8,5,2,2050,0), (8,5,2,2050,0),
(8,5,3,20554,0), (8,5,3,26297,0),
(8,5,10,159,128), (8,5,10,159,128),
(8,5,11,4540,128), (8,5,11,4540,128),
(8,6,0,6603,0), (8,6,0,6603,0),
@ -10449,17 +10449,17 @@ INSERT INTO `playercreateinfo_action` VALUES
(8,6,3,45462,0), (8,6,3,45462,0),
(8,6,4,45902,0), (8,6,4,45902,0),
(8,6,5,47541,0), (8,6,5,47541,0),
(8,6,10,50621,0), (8,6,10,26297,0),
(8,7,0,6603,0), (8,7,0,6603,0),
(8,7,1,403,0), (8,7,1,403,0),
(8,7,2,331,0), (8,7,2,331,0),
(8,7,3,20554,0), (8,7,3,26297,0),
(8,7,10,159,128), (8,7,10,159,128),
(8,7,11,117,128), (8,7,11,117,128),
(8,8,0,6603,0), (8,8,0,6603,0),
(8,8,1,133,0), (8,8,1,133,0),
(8,8,2,168,0), (8,8,2,168,0),
(8,8,3,20554,0), (8,8,3,26297,0),
(8,8,10,159,128), (8,8,10,159,128),
(8,8,11,117,128), (8,8,11,117,128),
(10,2,0,6603,0), (10,2,0,6603,0),
@ -12513,7 +12513,7 @@ INSERT INTO `playercreateinfo_spell` VALUES
(8,1,22027,'Remove Insignia'), (8,1,22027,'Remove Insignia'),
(8,1,22810,'Opening - No Text'), (8,1,22810,'Opening - No Text'),
(8,1,26290,'Bow Specialization'), (8,1,26290,'Bow Specialization'),
(8,1,26296,'Berserking'), (8,1,26297,'Berserking'),
(8,1,32215,'Victorious State'), (8,1,32215,'Victorious State'),
(8,1,45927,'Summon Friend'), (8,1,45927,'Summon Friend'),
(8,1,58943,'Da Voodoo Shuffle'), (8,1,58943,'Da Voodoo Shuffle'),
@ -12547,7 +12547,7 @@ INSERT INTO `playercreateinfo_spell` VALUES
(8,3,9078,'Cloth'), (8,3,9078,'Cloth'),
(8,3,9125,'Generic'), (8,3,9125,'Generic'),
(8,3,13358,'Defensive State (DND)'), (8,3,13358,'Defensive State (DND)'),
(8,3,20554,'Berserking'), (8,3,26297,'Berserking'),
(8,3,20555,'Regeneration'), (8,3,20555,'Regeneration'),
(8,3,20557,'Beast Slaying'), (8,3,20557,'Beast Slaying'),
(8,3,20558,'Throwing Specialization'), (8,3,20558,'Throwing Specialization'),
@ -12632,7 +12632,7 @@ INSERT INTO `playercreateinfo_spell` VALUES
(8,5,8386,'Attacking'), (8,5,8386,'Attacking'),
(8,5,9078,'Cloth'), (8,5,9078,'Cloth'),
(8,5,9125,'Generic'), (8,5,9125,'Generic'),
(8,5,20554,'Berserking'), (8,5,26297,'Berserking'),
(8,5,20555,'Regeneration'), (8,5,20555,'Regeneration'),
(8,5,20557,'Beast Slaying'), (8,5,20557,'Beast Slaying'),
(8,5,20558,'Throwing Specialization'), (8,5,20558,'Throwing Specialization'),
@ -12707,7 +12707,7 @@ INSERT INTO `playercreateinfo_spell` VALUES
(8,6,48266,'Blood Presence'), (8,6,48266,'Blood Presence'),
(8,6,49410,'Forceful Deflection'), (8,6,49410,'Forceful Deflection'),
(8,6,49576,'Death Grip'), (8,6,49576,'Death Grip'),
(8,6,50621,'Berserking'), (8,6,26297,'Berserking'),
(8,6,52665,'Sigil'), (8,6,52665,'Sigil'),
(8,6,58943,'Da Voodoo Shuffle'), (8,6,58943,'Da Voodoo Shuffle'),
(8,6,59879,'Blood Plague'), (8,6,59879,'Blood Plague'),
@ -12744,7 +12744,7 @@ INSERT INTO `playercreateinfo_spell` VALUES
(8,7,9078,'Cloth'), (8,7,9078,'Cloth'),
(8,7,9116,'Shield'), (8,7,9116,'Shield'),
(8,7,9125,'Generic'), (8,7,9125,'Generic'),
(8,7,20554,'Berserking'), (8,7,26297,'Berserking'),
(8,7,20555,'Regeneration'), (8,7,20555,'Regeneration'),
(8,7,20557,'Beast Slaying'), (8,7,20557,'Beast Slaying'),
(8,7,20558,'Throwing Specialization'), (8,7,20558,'Throwing Specialization'),
@ -12785,7 +12785,7 @@ INSERT INTO `playercreateinfo_spell` VALUES
(8,8,8386,'Attacking'), (8,8,8386,'Attacking'),
(8,8,9078,'Cloth'), (8,8,9078,'Cloth'),
(8,8,9125,'Generic'), (8,8,9125,'Generic'),
(8,8,20554,'Berserking'), (8,8,26297,'Berserking'),
(8,8,20555,'Regeneration'), (8,8,20555,'Regeneration'),
(8,8,20557,'Beast Slaying'), (8,8,20557,'Beast Slaying'),
(8,8,20558,'Throwing Specialization'), (8,8,20558,'Throwing Specialization'),
@ -17417,6 +17417,9 @@ INSERT INTO `spell_elixir` VALUES
(60346,0x1), (60346,0x1),
(60347,0x2), (60347,0x2),
(62380,0x3), (62380,0x3),
(67016,0x3),
(67017,0x3),
(67018,0x3),
(67019,0x3); (67019,0x3);

View file

@ -0,0 +1,9 @@
ALTER TABLE db_version CHANGE COLUMN required_8777_02_mangos_gameobject required_8800_01_mangos_spell_elixir bit;
DELETE FROM `spell_elixir` WHERE `entry` IN (67016,67017,67018);
/* Flasks added in 3.2.x */
INSERT INTO `spell_elixir` (`entry`, `mask`) VALUES
(67016,0x3),
(67017,0x3),
(67018,0x3);

View file

@ -0,0 +1,3 @@
ALTER TABLE db_version CHANGE COLUMN required_8800_01_mangos_spell_elixir required_8803_01_mangos_playercreateinfo_spell bit;
UPDATE `playercreateinfo_spell` SET `spell` = 26297 WHERE `spell` IN (20554,26296,50621);

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_8803_01_mangos_playercreateinfo_spell required_8803_02_mangos_playercreateinfo_action bit;
UPDATE `playercreateinfo_action`
SET `action` = 26297
WHERE `action` IN (20554,26296,50621) AND `type` = 0;

View file

@ -153,6 +153,9 @@ pkgdata_DATA = \
8775_03_mangos_gameobject.sql \ 8775_03_mangos_gameobject.sql \
8777_01_mangos_creature.sql \ 8777_01_mangos_creature.sql \
8777_02_mangos_gameobject.sql \ 8777_02_mangos_gameobject.sql \
8800_01_mangos_spell_elixir.sql \
8803_01_mangos_playercreateinfo_spell.sql \
8803_02_mangos_playercreateinfo_action.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -286,4 +289,7 @@ EXTRA_DIST = \
8775_03_mangos_gameobject.sql \ 8775_03_mangos_gameobject.sql \
8777_01_mangos_creature.sql \ 8777_01_mangos_creature.sql \
8777_02_mangos_gameobject.sql \ 8777_02_mangos_gameobject.sql \
8800_01_mangos_spell_elixir.sql \
8803_01_mangos_playercreateinfo_spell.sql \
8803_02_mangos_playercreateinfo_action.sql \
README README

View file

@ -55,5 +55,5 @@ class AccountMgr
static bool normalizeString(std::string& utf8str); static bool normalizeString(std::string& utf8str);
}; };
#define accmgr MaNGOS::Singleton<AccountMgr>::Instance() #define sAccountMgr MaNGOS::Singleton<AccountMgr>::Instance()
#endif #endif

View file

@ -97,7 +97,7 @@ void AuctionHouseMgr::SendAuctionWonMail( AuctionEntry *auction )
else else
{ {
bidder_accId = sObjectMgr.GetPlayerAccountIdByGUID(bidder_guid); bidder_accId = sObjectMgr.GetPlayerAccountIdByGUID(bidder_guid);
bidder_security = accmgr.GetSecurity(bidder_accId); bidder_security = sAccountMgr.GetSecurity(bidder_accId);
if(bidder_security > SEC_PLAYER ) // not do redundant DB requests if(bidder_security > SEC_PLAYER ) // not do redundant DB requests
{ {

View file

@ -1084,7 +1084,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
{ {
// a player has left the battleground, so there are free slots -> add to queue // a player has left the battleground, so there are free slots -> add to queue
AddToBGFreeSlotQueue(); AddToBGFreeSlotQueue();
sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, GetQueueId()); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId());
} }
// Let others know // Let others know

View file

@ -148,9 +148,8 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data )
// if we're here, then the conditions to join a bg are met. We can proceed in joining. // if we're here, then the conditions to join a bg are met. We can proceed in joining.
// _player->GetGroup() was already checked, grp is already initialized // _player->GetGroup() was already checked, grp is already initialized
BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0);
GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, bgTypeId, 0, false, isPremade, 0); uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
if (joinAsGroup /* && _player->GetGroup()*/) if (joinAsGroup /* && _player->GetGroup()*/)
{ {
sLog.outDebug("Battleground: the following players are joining as group:"); sLog.outDebug("Battleground: the following players are joining as group:");
@ -167,7 +166,7 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data )
member->GetSession()->SendPacket(&data); member->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
member->GetSession()->SendPacket(&data); member->GetSession()->SendPacket(&data);
bgQueue.AddPlayer(member, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
} }
sLog.outDebug("Battleground: group end"); sLog.outDebug("Battleground: group end");
@ -182,11 +181,12 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data )
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
SendPacket(&data); SendPacket(&data);
bgQueue.AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
} }
sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
//we should announce queue status here, if we want if (!ginfo->IsInvitedToBGInstanceGUID)
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
} }
void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ ) void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
@ -303,6 +303,7 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
uint8 type; // arenatype if arena uint8 type; // arenatype if arena
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
uint32 instanceId;
uint32 bgTypeId_; // type id from dbc uint32 bgTypeId_; // type id from dbc
uint16 unk; // 0x1F90 constant? uint16 unk; // 0x1F90 constant?
uint8 action; // enter battle 0x1, leave queue 0x0 uint8 action; // enter battle 0x1, leave queue 0x0
@ -311,130 +312,182 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{ {
sLog.outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_); sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_);
return; // update battleground slots for the player to fix his UI and sent data.
} // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
if (!_player->InBattleGroundQueue()) // it usually happens with extremely high latency (if debugging / stepping in the code for example)
{ if (_player->InBattleGroundQueue())
sLog.outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow()); {
// update all queues, send invitation info if player is invited, queue info if queued
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
if (!bgQueueTypeId)
continue;
BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
// if the player is not in queue, continue or no group information - this should never happen
if (itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo)
continue;
BattleGround * bg = NULL;
// get possibly needed data from groupinfo
uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
uint8 status = 0;
if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
{
// not invited to bg, get template
bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
status = STATUS_WAIT_QUEUE;
}
else
{
// get the bg we're invited to
bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
status = STATUS_WAIT_JOIN;
}
// if bg not found, then continue, don't invite if already in the instance
if (!bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()))
continue;
// re - invite player with proper data
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype);
SendPacket(&data);
}
}
return; return;
} }
//get GroupQueueInfo from BattleGroundQueue //get GroupQueueInfo from BattleGroundQueue
BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
//we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
GroupQueueInfo ginfo; if (itrPlayerStatus == qpMap.end())
if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
{ {
sLog.outError("BattlegroundHandler: itrplayerstatus not found."); sLog.outError("Battleground: itrplayerstatus not found.");
return;
}
// if action == 1, then instanceId is required
if (!ginfo.IsInvitedToBGInstanceGUID && action == 1)
{
sLog.outError("BattlegroundHandler: instance not found.");
return; return;
} }
BattleGround *bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
// if action == 1, then instanceId is required
if (!instanceId && action == 1)
{
sLog.outError("Battleground: instance not found.");
return;
}
BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
// bg template might and must be used in case of leaving queue, when instance is not created yet // bg template might and must be used in case of leaving queue, when instance is not created yet
if (!bg && action == 0) if (!bg && action == 0)
bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
if (!bg) if (!bg)
{ {
sLog.outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId);
return; return;
} }
//some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it if (_player->InBattleGroundQueue())
if (action == 1 && ginfo.ArenaType == 0)
{ {
//if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function!
if (!_player->CanJoinToBattleground()) uint32 team = itrPlayerStatus->second.GroupInfo->Team;
uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType;
uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated;
uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating;
uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating;
//some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
if (action == 1 && arenaType == 0)
{ {
//send bg command result to show nice message //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4); if (!_player->CanJoinToBattleground())
data2 << uint32(0xFFFFFFFE); {
_player->GetSession()->SendPacket(&data2); //send bg command result to show nice message
action = 0; WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); data2 << uint32(0xFFFFFFFE);
_player->GetSession()->SendPacket(&data2);
action = 0;
sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
}
//if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
if (_player->getLevel() > bg->GetMaxLevel())
{
sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
action = 0;
}
} }
//if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
if (_player->getLevel() > bg->GetMaxLevel()) WorldPacket data;
switch( action )
{ {
sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); case 1: // port to battleground
action = 0; if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
} return; // cheating?
}
uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
WorldPacket data;
switch( action )
{
case 1: // port to battleground
if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
return; // cheating?
_player->SetBattleGroundEntryPoint(); _player->SetBattleGroundEntryPoint();
// resurrect the player // resurrect the player
if (!_player->isAlive()) if (!_player->isAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
// stop taxi flight at port
if (_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
_player->m_taxi.ClearTaxiDestinations();
}
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
_player->GetSession()->SendPacket(&data);
// remove battleground queue status from BGmgr
bgQueue.RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
// also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
if (BattleGround *currentBg = _player->GetBattleGround())
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
// set the destination instance id
_player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
// set the destination team
_player->SetBGTeam(ginfo.Team);
// bg->HandleBeforeTeleportToBattleGround(_player);
sBattleGroundMgr.SendToBattleGround(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
// add only in HandleMoveWorldPortAck()
// bg->AddPlayer(_player,team);
sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId);
break;
case 0: // leave queue
// if player leaves rated arena match before match start, it is counted as he played but he lost
if (ginfo.IsRated)
{
ArenaTeam * at = sObjectMgr.GetArenaTeamById(ginfo.Team);
if (at)
{ {
sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); _player->ResurrectPlayer(1.0f);
at->MemberLost(_player, ginfo.OpponentsTeamRating); _player->SpawnCorpseBones();
at->SaveToDB();
} }
} // stop taxi flight at port
_player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs if (_player->isInFlight())
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); {
bgQueue.RemovePlayer(_player->GetGUID(), true); _player->GetMotionMaster()->MovementExpired();
// player left queue, we should update it - do not update Arena Queue _player->m_taxi.ClearTaxiDestinations();
if (!ginfo.ArenaType) }
sBattleGroundMgr.ScheduleQueueUpdate(ginfo.ArenaTeamRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
SendPacket(&data); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); _player->GetSession()->SendPacket(&data);
break; // remove battleground queue status from BGmgr
default: sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
sLog.outError("Battleground port: unknown action %u", action); // this is still needed here if battleground "jumping" shouldn't add deserter debuff
break; // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
if (BattleGround *currentBg = _player->GetBattleGround())
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
// set the destination instance id
_player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
// set the destination team
_player->SetBGTeam(team);
// bg->HandleBeforeTeleportToBattleGround(_player);
sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId);
// add only in HandleMoveWorldPortAck()
// bg->AddPlayer(_player,team);
sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId);
break;
case 0: // leave queue
// if player leaves rated arena match before match start, it is counted as he played but he lost
if (isRated)
{
ArenaTeam * at = sObjectMgr.GetArenaTeamById(team);
if (at)
{
sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating);
at->MemberLost(_player, opponentsRating);
at->SaveToDB();
}
}
_player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
// player left queue, we should update it - do not update Arena Queue
if (!arenaType)
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenaType, isRated, rating);
SendPacket(&data);
sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
break;
default:
sLog.outError("Battleground port: unknown action %u", action);
break;
}
} }
} }
@ -491,16 +544,16 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
} }
//we are sending update to player about queue - he can be invited there! //we are sending update to player about queue - he can be invited there!
//get GroupQueueInfo for queue status //get GroupQueueInfo for queue status
BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
GroupQueueInfo ginfo; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) if (itrPlayerStatus == qpMap.end())
continue; continue;
if (ginfo.IsInvitedToBGInstanceGUID) if (itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
{ {
bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
if (!bg) if (!bg)
continue; continue;
uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime);
// send status invited to BattleGround // send status invited to BattleGround
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
SendPacket(&data); SendPacket(&data);
@ -510,9 +563,9 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
if (!bg) if (!bg)
continue; continue;
uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, _player->GetBattleGroundQueueIdFromLevel()); uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel());
// send status in BattleGround Queue // send status in BattleGround Queue
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType);
SendPacket(&data); SendPacket(&data);
} }
} }
@ -672,9 +725,8 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
arenaRating = avg_pers_rating; arenaRating = avg_pers_rating;
} }
BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId); uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
if (asGroup) if (asGroup)
{ {
sLog.outDebug("Battleground: arena join as group start"); sLog.outDebug("Battleground: arena join as group start");
@ -693,11 +745,12 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
member->GetSession()->SendPacket(&data); member->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
member->GetSession()->SendPacket(&data); member->GetSession()->SendPacket(&data);
bgQueue.AddPlayer(member, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
} }
sLog.outDebug("Battleground: arena join as group end"); sLog.outDebug("Battleground: arena join as group end");
//announce to world ... removed if (isRated)
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
} }
else else
{ {
@ -707,10 +760,10 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
// send status packet (in queue) // send status packet (in queue)
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
SendPacket(&data); SendPacket(&data);
bgQueue.AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
} }
sBattleGroundMgr.ScheduleQueueUpdate(arenaRating, arenatype, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
} }
void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data ) void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data )

View file

@ -177,7 +177,6 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId
index++; index++;
sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index); sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index);
ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
m_QueuedGroups[queue_id][index].push_back(ginfo); m_QueuedGroups[queue_id][index].push_back(ginfo);
// return ginfo, because it is needed to add players to this group info // return ginfo, because it is needed to add players to this group info
@ -187,8 +186,6 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId
//add player to playermap //add player to playermap
void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo) void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
{ {
ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
//if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()]; PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()];
info.LastOnlineTime = getMSTime(); info.LastOnlineTime = getMSTime();
@ -251,7 +248,6 @@ uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueue
void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount) void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
{ {
//Player *plr = sObjectMgr.GetPlayer(guid); //Player *plr = sObjectMgr.GetPlayer(guid);
ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
int32 queue_id = -1; // signed for proper for-loop finish int32 queue_id = -1; // signed for proper for-loop finish
QueuedPlayersMap::iterator itr; QueuedPlayersMap::iterator itr;
@ -368,26 +364,6 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou
} }
} }
//returns true when player pl_guid is in queue and is invited to bgInstanceGuid
bool BattleGroundQueue::IsPlayerInvited(const uint64& pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime)
{
ACE_Guard<ACE_Recursive_Thread_Mutex> g(m_Lock);
QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(pl_guid);
return ( qItr != m_QueuedPlayers.end()
&& qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == bgInstanceGuid
&& qItr->second.GroupInfo->RemoveInviteTime == removeTime );
}
bool BattleGroundQueue::GetPlayerGroupInfoData(const uint64& guid, GroupQueueInfo* ginfo)
{
ACE_Guard<ACE_Recursive_Thread_Mutex> g(m_Lock);
QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(guid);
if (qItr == m_QueuedPlayers.end())
return false;
*ginfo = *(qItr->second.GroupInfo);
return true;
}
//Announce world message //Announce world message
void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue) void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
{ {
@ -485,7 +461,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b
plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID); plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID);
// create remind invite events // create remind invite events
BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->ArenaType, ginfo->RemoveInviteTime); BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime);
plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME)); plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
// create automatic remove events // create automatic remove events
BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime); BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime);
@ -756,7 +732,6 @@ should be called from BattleGround::RemovePlayer function in some cases
*/ */
void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating) void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating)
{ {
ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
//if no players in queue - do nothing //if no players in queue - do nothing
if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() && m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
@ -1046,15 +1021,17 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue or in battleground if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue or in battleground
{ {
// check if player is invited to this bg // check if player is invited to this bg
BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime)) BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
if( qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
&& qItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
{ {
WorldPacket data; WorldPacket data;
//we must send remaining time in queue //we must send remaining time in queue
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType);
plr->GetSession()->SendPacket(&data); plr->GetSession()->SendPacket(&data);
} }
} }
@ -1087,19 +1064,22 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
//bg pointer can be NULL! so use it carefully! //bg pointer can be NULL! so use it carefully!
uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId); uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId);
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue, or in Battleground if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue, or in Battleground
{ {
// check if player is in queue for this BG and if we are removing his invite event // check if player is in queue for this BG and if we are removing his invite event
BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId]; BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].m_QueuedPlayers;
if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime)) BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
if( qMapItr != qpMap.end() && qMapItr->second.GroupInfo
&& qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
&& qMapItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
{ {
sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID); sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
plr->RemoveBattleGroundQueueId(m_BgQueueTypeId); plr->RemoveBattleGroundQueueId(m_BgQueueTypeId);
bgQueue.RemovePlayer(m_PlayerGuid, true); sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
//update queues if battleground isn't ended //update queues if battleground isn't ended
if (bg && bg->isBattleGround() && bg->GetStatus() != STATUS_WAIT_LEAVE) if (bg)
sBattleGroundMgr.ScheduleQueueUpdate(0, 0, m_BgQueueTypeId, m_BgTypeId, bg->GetQueueId()); sBattleGroundMgr.ScheduleQueueUpdate(m_BgQueueTypeId, m_BgTypeId, bg->GetQueueId());
WorldPacket data; WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
@ -1187,24 +1167,18 @@ void BattleGroundMgr::Update(uint32 diff)
// update scheduled queues // update scheduled queues
if (!m_QueueUpdateScheduler.empty()) if (!m_QueueUpdateScheduler.empty())
{ {
std::vector<uint64> scheduled; //copy vector and clear the other
{ // TODO add lock
//create mutex // TODO maybe std::list would be better and then unlock after end of cycle
ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock); std::vector<uint32> scheduled(m_QueueUpdateScheduler);
//copy vector and clear the other m_QueueUpdateScheduler.clear();
scheduled = std::vector<uint64>(m_QueueUpdateScheduler); // TODO drop lock
m_QueueUpdateScheduler.clear();
//release lock
}
for (uint8 i = 0; i < scheduled.size(); i++) for (uint8 i = 0; i < scheduled.size(); i++)
{ {
uint32 arenaRating = scheduled[i] >> 32; BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16);
uint8 arenaType = scheduled[i] >> 24 & 255;
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16 & 255);
BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] >> 8) & 255); BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] >> 8) & 255);
BGQueueIdBasedOnLevel queue_id = BGQueueIdBasedOnLevel(scheduled[i] & 255); BGQueueIdBasedOnLevel queue_id = BGQueueIdBasedOnLevel(scheduled[i] & 255);
m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id, arenaType, arenaRating > 0, arenaRating); m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id);
} }
} }
@ -2035,11 +2009,11 @@ void BattleGroundMgr::ToggleArenaTesting()
sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF); sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
} }
void BattleGroundMgr::ScheduleQueueUpdate(uint32 arenaRating, uint8 arenaType, BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id) void BattleGroundMgr::ScheduleQueueUpdate(BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
{ {
ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock); //This method must be atomic, TODO add mutex
//we will use only 1 number created of bgTypeId and queue_id //we will use only 1 number created of bgTypeId and queue_id
uint64 schedule_id = ((uint64)arenaRating << 32) | (arenaType << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | queue_id; uint32 schedule_id = (bgQueueTypeId << 16) | (bgTypeId << 8) | queue_id;
bool found = false; bool found = false;
for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++) for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++)
{ {

View file

@ -23,7 +23,6 @@
#include "Policies/Singleton.h" #include "Policies/Singleton.h"
#include "Utilities/EventProcessor.h" #include "Utilities/EventProcessor.h"
#include "BattleGround.h" #include "BattleGround.h"
#include "ace/Recursive_Thread_Mutex.h"
typedef std::map<uint32, BattleGround*> BattleGroundSet; typedef std::map<uint32, BattleGround*> BattleGroundSet;
@ -84,19 +83,12 @@ class BattleGroundQueue
GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0); GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0);
void AddPlayer(Player *plr, GroupQueueInfo *ginfo); void AddPlayer(Player *plr, GroupQueueInfo *ginfo);
void RemovePlayer(const uint64& guid, bool decreaseInvitedCount); void RemovePlayer(const uint64& guid, bool decreaseInvitedCount);
bool IsPlayerInvited(const uint64& pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime);
bool GetPlayerGroupInfoData(const uint64& guid, GroupQueueInfo* ginfo);
void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id);
uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id);
void DecreaseGroupLength(uint32 queueId, uint32 AsGroup); void DecreaseGroupLength(uint32 queueId, uint32 AsGroup);
void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue); void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue);
private:
//mutex that should not allow changing private data, nor allowing to update Queue during private data change.
ACE_Recursive_Thread_Mutex m_Lock;
typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap; typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap;
QueuedPlayersMap m_QueuedPlayers; QueuedPlayersMap m_QueuedPlayers;
@ -131,6 +123,8 @@ class BattleGroundQueue
//one selection pool for horde, other one for alliance //one selection pool for horde, other one for alliance
SelectionPool m_SelectionPools[BG_TEAMS_COUNT]; SelectionPool m_SelectionPools[BG_TEAMS_COUNT];
private:
bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side); bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side);
uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME]; uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES]; uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES];
@ -144,8 +138,8 @@ class BattleGroundQueue
class BGQueueInviteEvent : public BasicEvent class BGQueueInviteEvent : public BasicEvent
{ {
public: public:
BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId, uint8 arenaType, uint32 removeTime) : BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 removeTime) :
m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId), m_ArenaType(arenaType), m_RemoveTime(removeTime) m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId), m_RemoveTime(removeTime)
{ {
}; };
virtual ~BGQueueInviteEvent() {}; virtual ~BGQueueInviteEvent() {};
@ -156,7 +150,6 @@ class BGQueueInviteEvent : public BasicEvent
uint64 m_PlayerGuid; uint64 m_PlayerGuid;
uint32 m_BgInstanceGUID; uint32 m_BgInstanceGUID;
BattleGroundTypeId m_BgTypeId; BattleGroundTypeId m_BgTypeId;
uint8 m_ArenaType;
uint32 m_RemoveTime; uint32 m_RemoveTime;
}; };
@ -226,7 +219,7 @@ class BattleGroundMgr
BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPE_ID]; BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPE_ID];
void ScheduleQueueUpdate(uint32 arenaRating, uint8 arenaType, BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); void ScheduleQueueUpdate(BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id);
uint32 GetMaxRatingDifference() const; uint32 GetMaxRatingDifference() const;
uint32 GetRatingDiscardTimer() const; uint32 GetRatingDiscardTimer() const;
uint32 GetPrematureFinishTime() const; uint32 GetPrematureFinishTime() const;
@ -272,14 +265,13 @@ class BattleGroundMgr
static bool IsBGWeekend(BattleGroundTypeId bgTypeId); static bool IsBGWeekend(BattleGroundTypeId bgTypeId);
private: private:
ACE_Thread_Mutex SchedulerLock;
BattleMastersMap mBattleMastersMap; BattleMastersMap mBattleMastersMap;
CreatureBattleEventIndexesMap m_CreatureBattleEventIndexMap; CreatureBattleEventIndexesMap m_CreatureBattleEventIndexMap;
GameObjectBattleEventIndexesMap m_GameObjectBattleEventIndexMap; GameObjectBattleEventIndexesMap m_GameObjectBattleEventIndexMap;
/* Battlegrounds */ /* Battlegrounds */
BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID]; BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID];
std::vector<uint64> m_QueueUpdateScheduler; std::vector<uint32>m_QueueUpdateScheduler;
std::set<uint32> m_ClientBattleGroundIds[MAX_BATTLEGROUND_TYPE_ID][MAX_BATTLEGROUND_QUEUES]; //the instanceids just visible for the client std::set<uint32> m_ClientBattleGroundIds[MAX_BATTLEGROUND_TYPE_ID][MAX_BATTLEGROUND_QUEUES]; //the instanceids just visible for the client
uint32 m_NextRatingDiscardUpdate; uint32 m_NextRatingDiscardUpdate;
time_t m_NextAutoDistributionTime; time_t m_NextAutoDistributionTime;

View file

@ -725,7 +725,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac
if (target) if (target)
target_sec = target->GetSecurity(); target_sec = target->GetSecurity();
else if (target_account) else if (target_account)
target_sec = accmgr.GetSecurity(target_account); target_sec = sAccountMgr.GetSecurity(target_account);
else else
return true; // caller must report error for (target==NULL && target_account==0) return true; // caller must report error for (target==NULL && target_account==0)

View file

@ -200,14 +200,14 @@ bool ChatHandler::HandleAccountPasswordCommand(const char* args)
return false; return false;
} }
if (!accmgr.CheckPassword (m_session->GetAccountId(), password_old)) if (!sAccountMgr.CheckPassword (m_session->GetAccountId(), password_old))
{ {
SendSysMessage (LANG_COMMAND_WRONGOLDPASSWORD); SendSysMessage (LANG_COMMAND_WRONGOLDPASSWORD);
SetSentErrorMessage (true); SetSentErrorMessage (true);
return false; return false;
} }
AccountOpResult result = accmgr.ChangePassword(m_session->GetAccountId(), password_new); AccountOpResult result = sAccountMgr.ChangePassword(m_session->GetAccountId(), password_new);
switch(result) switch(result)
{ {

View file

@ -863,7 +863,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args)
arg2 = arg1; arg2 = arg1;
targetAccountId = targetPlayer->GetSession()->GetAccountId(); targetAccountId = targetPlayer->GetSession()->GetAccountId();
accmgr.GetName(targetAccountId, targetAccountName); sAccountMgr.GetName(targetAccountId, targetAccountName);
} }
else else
{ {
@ -879,7 +879,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args)
return false; return false;
} }
targetAccountId = accmgr.GetId(targetAccountName); targetAccountId = sAccountMgr.GetId(targetAccountName);
if(!targetAccountId) if(!targetAccountId)
{ {
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,targetAccountName.c_str()); PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,targetAccountName.c_str());
@ -945,7 +945,7 @@ bool ChatHandler::HandleAccountSetPasswordCommand(const char* args)
return false; return false;
} }
uint32 targetAccountId = accmgr.GetId(account_name); uint32 targetAccountId = sAccountMgr.GetId(account_name);
if (!targetAccountId) if (!targetAccountId)
{ {
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
@ -965,7 +965,7 @@ bool ChatHandler::HandleAccountSetPasswordCommand(const char* args)
return false; return false;
} }
AccountOpResult result = accmgr.ChangePassword(targetAccountId, szPassword1); AccountOpResult result = sAccountMgr.ChangePassword(targetAccountId, szPassword1);
switch(result) switch(result)
{ {
@ -5027,7 +5027,7 @@ bool ChatHandler::HandleBanInfoAccountCommand(const char* args)
return false; return false;
} }
uint32 accountid = accmgr.GetId(account_name); uint32 accountid = sAccountMgr.GetId(account_name);
if (!accountid) if (!accountid)
{ {
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
@ -5047,7 +5047,7 @@ bool ChatHandler::HandleBanInfoCharacterCommand(const char* args)
uint32 accountid = target ? target->GetSession()->GetAccountId() : sObjectMgr.GetPlayerAccountIdByGUID(target_guid); uint32 accountid = target ? target->GetSession()->GetAccountId() : sObjectMgr.GetPlayerAccountIdByGUID(target_guid);
std::string accountname; std::string accountname;
if (!accmgr.GetName(accountid,accountname)) if (!sAccountMgr.GetName(accountid,accountname))
{ {
PSendSysMessage(LANG_BANINFO_NOCHARACTER); PSendSysMessage(LANG_BANINFO_NOCHARACTER);
return true; return true;
@ -5206,7 +5206,7 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result)
account_name = fields[1].GetCppString(); account_name = fields[1].GetCppString();
// "character" case, name need extract from another DB // "character" case, name need extract from another DB
else else
accmgr.GetName (account_id,account_name); sAccountMgr.GetName (account_id,account_name);
// No SQL injection. id is uint32. // No SQL injection. id is uint32.
QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id); QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id);
@ -5400,7 +5400,7 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args)
return false; return false;
} }
uint32 account_id = accmgr.GetId(account_name); uint32 account_id = sAccountMgr.GetId(account_name);
if (!account_id) if (!account_id)
{ {
account_id = atoi(account); // use original string account_id = atoi(account); // use original string
@ -5412,7 +5412,7 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args)
} }
} }
if (!accmgr.GetName(account_id,account_name)) if (!sAccountMgr.GetName(account_id,account_name))
{ {
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
SetSentErrorMessage(true); SetSentErrorMessage(true);
@ -6100,7 +6100,7 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
return false; return false;
account_id = player->GetSession()->GetAccountId(); account_id = player->GetSession()->GetAccountId();
accmgr.GetName(account_id,account_name); sAccountMgr.GetName(account_id,account_name);
szExp = szAcc; szExp = szAcc;
} }
else else
@ -6114,7 +6114,7 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
return false; return false;
} }
account_id = accmgr.GetId(account_name); account_id = sAccountMgr.GetId(account_name);
if (!account_id) if (!account_id)
{ {
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());

View file

@ -50,6 +50,11 @@ void WorldSession::HandleMoveWorldportAckOpcode()
// possible errors in the coordinate validity check // possible errors in the coordinate validity check
if(!MapManager::IsValidMapCoord(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation)) if(!MapManager::IsValidMapCoord(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation))
{ {
sLog.outError("WorldSession::HandleMoveWorldportAckOpcode: player got's teleported far to a not valid location. (map:%u, x:%f, y:%f, z:%f) We log him out and don't save him..", loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z);
// stop teleportation else we would try this again in the beginning of WorldSession::LogoutPlayer...
GetPlayer()->SetSemaphoreTeleportFar(false);
// player don't gets saved - so his coords will stay at the point where
// he was last saved
LogoutPlayer(false); LogoutPlayer(false);
return; return;
} }

View file

@ -2495,8 +2495,15 @@ void ObjectMgr::LoadPlayerInfo()
continue; continue;
} }
uint32 spell_id = fields[2].GetUInt32();
if (!sSpellStore.LookupEntry(spell_id))
{
sLog.outErrorDb("Non existing spell %u in `playercreateinfo_spell` table, ignoring.", spell_id);
continue;
}
PlayerInfo* pInfo = &playerInfo[current_race][current_class]; PlayerInfo* pInfo = &playerInfo[current_race][current_class];
pInfo->spell.push_back(fields[2].GetUInt32()); pInfo->spell.push_back(spell_id);
bar.step(); bar.step();
++count; ++count;
@ -2547,8 +2554,15 @@ void ObjectMgr::LoadPlayerInfo()
continue; continue;
} }
uint8 action_button = fields[2].GetUInt8();
uint32 action = fields[3].GetUInt32();
uint8 action_type = fields[4].GetUInt8();
if (!Player::IsActionButtonDataValid(action_button,action,action_type,NULL))
continue;
PlayerInfo* pInfo = &playerInfo[current_race][current_class]; PlayerInfo* pInfo = &playerInfo[current_race][current_class];
pInfo->action.push_back(PlayerCreateInfoAction(fields[2].GetUInt8(),fields[3].GetUInt32(),fields[4].GetUInt8())); pInfo->action.push_back(PlayerCreateInfoAction(action_button,action,action_type));
bar.step(); bar.step();
++count; ++count;

View file

@ -666,7 +666,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x27D*/ { "CMSG_ENABLE_DAMAGE_LOG", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x27D*/ { "CMSG_ENABLE_DAMAGE_LOG", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x27E*/ { "CMSG_GROUP_CHANGE_SUB_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleGroupChangeSubGroupOpcode }, /*0x27E*/ { "CMSG_GROUP_CHANGE_SUB_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleGroupChangeSubGroupOpcode },
/*0x27F*/ { "CMSG_REQUEST_PARTY_MEMBER_STATS", STATUS_LOGGEDIN, &WorldSession::HandleRequestPartyMemberStatsOpcode}, /*0x27F*/ { "CMSG_REQUEST_PARTY_MEMBER_STATS", STATUS_LOGGEDIN, &WorldSession::HandleRequestPartyMemberStatsOpcode},
/*0x280*/ { "CMSG_GROUP_SWAP_SUB_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x280*/ { "CMSG_GROUP_SWAP_SUB_GROUP", STATUS_UNHANDLED,&WorldSession::Handle_NULL },
/*0x281*/ { "CMSG_RESET_FACTION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x281*/ { "CMSG_RESET_FACTION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x282*/ { "CMSG_AUTOSTORE_BANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBankItemOpcode }, /*0x282*/ { "CMSG_AUTOSTORE_BANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBankItemOpcode },
/*0x283*/ { "CMSG_AUTOBANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoBankItemOpcode }, /*0x283*/ { "CMSG_AUTOBANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoBankItemOpcode },
@ -684,7 +684,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupAssistantLeaderOpcode}, /*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupAssistantLeaderOpcode},
/*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuybackItem }, /*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuybackItem },
/*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x292*/ { "CMSG_SET_SAVED_INSTANCE_EXTEND", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x292*/ { "CMSG_SET_SAVED_INSTANCE_EXTEND", STATUS_UNHANDLED,&WorldSession::Handle_NULL },
/*0x293*/ { "SMSG_MEETINGSTONE_LEAVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x293*/ { "SMSG_MEETINGSTONE_LEAVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x294*/ { "CMSG_MEETINGSTONE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x294*/ { "CMSG_MEETINGSTONE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x295*/ { "SMSG_MEETINGSTONE_SETQUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x295*/ { "SMSG_MEETINGSTONE_SETQUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
@ -772,7 +772,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x2E7*/ { "CMSG_WARDEN_DATA", STATUS_LOGGEDIN, &WorldSession::HandleWardenDataOpcode }, /*0x2E7*/ { "CMSG_WARDEN_DATA", STATUS_LOGGEDIN, &WorldSession::HandleWardenDataOpcode },
/*0x2E8*/ { "SMSG_GROUP_JOINED_BATTLEGROUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x2E8*/ { "SMSG_GROUP_JOINED_BATTLEGROUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x2E9*/ { "MSG_BATTLEGROUND_PLAYER_POSITIONS", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPositionsOpcode}, /*0x2E9*/ { "MSG_BATTLEGROUND_PLAYER_POSITIONS", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPositionsOpcode},
/*0x2EA*/ { "CMSG_PET_STOP_ATTACK", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x2EA*/ { "CMSG_PET_STOP_ATTACK", STATUS_UNHANDLED,&WorldSession::Handle_NULL },
/*0x2EB*/ { "SMSG_BINDER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x2EB*/ { "SMSG_BINDER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x2EC*/ { "SMSG_BATTLEGROUND_PLAYER_JOINED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x2EC*/ { "SMSG_BATTLEGROUND_PLAYER_JOINED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x2ED*/ { "SMSG_BATTLEGROUND_PLAYER_LEFT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x2ED*/ { "SMSG_BATTLEGROUND_PLAYER_LEFT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
@ -1066,7 +1066,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x40D*/ { "CMSG_GRANT_LEVEL", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x40D*/ { "CMSG_GRANT_LEVEL", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x40E*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x40E*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x40F*/ { "MSG_GM_CHANGE_ARENA_RATING", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x40F*/ { "MSG_GM_CHANGE_ARENA_RATING", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x410*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x410*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_UNHANDLED,&WorldSession::Handle_NULL },
/*0x411*/ { "SMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x411*/ { "SMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x412*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x412*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x413*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x413*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
@ -1206,7 +1206,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x499*/ { "SMSG_PET_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x499*/ { "SMSG_PET_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x49A*/ { "SMSG_PET_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x49A*/ { "SMSG_PET_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x49C*/ { "CMSG_HEARTH_AND_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x49C*/ { "CMSG_HEARTH_AND_RESURRECT", STATUS_UNHANDLED,&WorldSession::Handle_NULL },
/*0x49D*/ { "SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x49D*/ { "SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x49E*/ { "SMSG_CRITERIA_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x49E*/ { "SMSG_CRITERIA_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x49F*/ { "SMSG_ACHIEVEMENT_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x49F*/ { "SMSG_ACHIEVEMENT_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide },

View file

@ -1330,7 +1330,8 @@ enum SessionStatus
STATUS_LOGGEDIN, ///< Player in game (_player!=NULL, m_GUID == _player->GetGUID(), inWorld()) STATUS_LOGGEDIN, ///< Player in game (_player!=NULL, m_GUID == _player->GetGUID(), inWorld())
STATUS_TRANSFER, ///< Player transferring to another map (_player!=NULL, m_GUID == _player->GetGUID(), !inWorld()) STATUS_TRANSFER, ///< Player transferring to another map (_player!=NULL, m_GUID == _player->GetGUID(), !inWorld())
STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, ///< _player!= NULL or _player==NULL && m_playerRecentlyLogout, m_GUID store last _player guid) STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, ///< _player!= NULL or _player==NULL && m_playerRecentlyLogout, m_GUID store last _player guid)
STATUS_NEVER ///< Opcode not accepted from client (deprecated or server side only) STATUS_NEVER, ///< Opcode not accepted from client (deprecated or server side only)
STATUS_UNHANDLED ///< We don' handle this opcode yet
}; };
class WorldPacket; class WorldPacket;

View file

@ -5547,18 +5547,24 @@ void Player::SendInitialActionButtons() const
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() ); sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
} }
ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type) bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type, Player* player)
{ {
if(button >= MAX_ACTION_BUTTONS) if(button >= MAX_ACTION_BUTTONS)
{ {
sLog.outError( "Action %u not added into button %u for player %s: button must be < 144", action, button, GetName() ); if (player)
return NULL; sLog.outError( "Action %u not added into button %u for player %s: button must be < %u", action, button, player->GetName(), MAX_ACTION_BUTTONS );
else
sLog.outError( "Table `playercreateinfo_action` have action %u into button %u : button must be < %u", action, button, MAX_ACTION_BUTTONS );
return false;
} }
if(action >= MAX_ACTION_BUTTON_ACTION_VALUE) if(action >= MAX_ACTION_BUTTON_ACTION_VALUE)
{ {
sLog.outError( "Action %u not added into button %u for player %s: action must be < %u", action, button, GetName(), MAX_ACTION_BUTTON_ACTION_VALUE ); if (player)
return NULL; sLog.outError( "Action %u not added into button %u for player %s: action must be < %u", action, button, player->GetName(), MAX_ACTION_BUTTON_ACTION_VALUE );
else
sLog.outError( "Table `playercreateinfo_action` have action %u into button %u : action must be < %u", action, button, MAX_ACTION_BUTTON_ACTION_VALUE );
return false;
} }
switch(type) switch(type)
@ -5566,27 +5572,41 @@ ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
case ACTION_BUTTON_SPELL: case ACTION_BUTTON_SPELL:
if(!sSpellStore.LookupEntry(action)) if(!sSpellStore.LookupEntry(action))
{ {
sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() ); if (player)
return NULL; sLog.outError( "Spell action %u not added into button %u for player %s: spell not exist", action, button, player->GetName() );
else
sLog.outError( "Table `playercreateinfo_action` have spell action %u into button %u: spell not exist", action, button );
return false;
} }
if(!HasSpell(action)) if(player && !player->HasSpell(action))
{ {
sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() ); sLog.outError( "Spell action %u not added into button %u for player %s: player don't known this spell", action, button, player->GetName() );
return NULL; return false;
} }
break; break;
case ACTION_BUTTON_ITEM: case ACTION_BUTTON_ITEM:
if(!ObjectMgr::GetItemPrototype(action)) if(!ObjectMgr::GetItemPrototype(action))
{ {
sLog.outError( "Action %u not added into button %u for player %s: item not exist", action, button, GetName() ); if (player)
return NULL; sLog.outError( "Item action %u not added into button %u for player %s: item not exist", action, button, player->GetName() );
else
sLog.outError( "Table `playercreateinfo_action` have item action %u into button %u: item not exist", action, button );
return false;
} }
break; break;
default: default:
break; // pther cases not checked at this moment break; // other cases not checked at this moment
} }
return true;
}
ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
{
if (!IsActionButtonDataValid(button,action,type,this))
return NULL;
// it create new button (NEW state) if need or return existed // it create new button (NEW state) if need or return existed
ActionButton& ab = m_actionButtons[button]; ActionButton& ab = m_actionButtons[button];

View file

@ -1628,6 +1628,7 @@ class MANGOS_DLL_SPEC Player : public Unit
m_cinematic = cine; m_cinematic = cine;
} }
static bool IsActionButtonDataValid(uint8 button, uint32 action, uint8 type, Player* player);
ActionButton* addActionButton(uint8 button, uint32 action, uint8 type); ActionButton* addActionButton(uint8 button, uint32 action, uint8 type);
void removeActionButton(uint8 button); void removeActionButton(uint8 button);
void SendInitialActionButtons() const; void SendInitialActionButtons() const;

View file

@ -1194,7 +1194,11 @@ enum GameObjectFlags
GO_FLAG_TRANSPORT = 0x00000008, //any kind of transport? Object can transport (elevator, boat, car) GO_FLAG_TRANSPORT = 0x00000008, //any kind of transport? Object can transport (elevator, boat, car)
GO_FLAG_UNK1 = 0x00000010, // GO_FLAG_UNK1 = 0x00000010, //
GO_FLAG_NODESPAWN = 0x00000020, //never despawn, typically for doors, they just change state GO_FLAG_NODESPAWN = 0x00000020, //never despawn, typically for doors, they just change state
GO_FLAG_TRIGGERED = 0x00000040 //typically, summoned objects. Triggered by spell or other events GO_FLAG_TRIGGERED = 0x00000040, //typically, summoned objects. Triggered by spell or other events
GO_FLAG_UNK_8 = 0x00000080,
GO_FLAG_UNK_9 = 0x00000100, //? Seen on type 33, possible meaning "destruct in progress"
GO_FLAG_UNK_10 = 0x00000200, //? Seen on type 33
GO_FLAG_UNK_11 = 0x00000400 //? Seen on type 33, possibly meaning "destructed"
}; };
enum TextEmotes enum TextEmotes

View file

@ -1994,6 +1994,9 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap)
SpellTargetPosition const* st = sSpellMgr.GetSpellTargetPosition(m_spellInfo->Id); SpellTargetPosition const* st = sSpellMgr.GetSpellTargetPosition(m_spellInfo->Id);
if(st) if(st)
{ {
// teleportspells are handled in another way
if (m_spellInfo->Effect[effIndex] == SPELL_EFFECT_TELEPORT_UNITS)
break;
if (st->target_mapId == m_caster->GetMapId()) if (st->target_mapId == m_caster->GetMapId())
m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); m_targets.setDestination(st->target_X, st->target_Y, st->target_Z);
else else

View file

@ -1321,6 +1321,22 @@ void Spell::EffectDummy(uint32 i)
return; return;
m_caster->CastSpell(unitTarget,60934,true,NULL); m_caster->CastSpell(unitTarget,60934,true,NULL);
return; return;
case 67019: // Flask of the North
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id;
switch(urand(1, 3))
{
case 1: spell_id = 67016; break;
case 2: spell_id = 67017; break;
default:spell_id = 67018; break;
}
m_caster->CastSpell(m_caster, spell_id, true, NULL);
return;
}
} }
break; break;
} }

View file

@ -68,6 +68,10 @@ void Totem::Summon(Unit* owner)
AIM_Initialize(); AIM_Initialize();
// there are some totems, which exist just for their visual appeareance
if (!GetSpell())
return;
switch(m_type) switch(m_type)
{ {
case TOTEM_PASSIVE: case TOTEM_PASSIVE:

View file

@ -83,7 +83,10 @@ void WaypointManager::Load()
sLog.outString( ">> Paths loaded" ); sLog.outString( ">> Paths loaded" );
} }
result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point FROM creature_movement"); // 0 1 2 3 4 5
result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2,"
// 6 7 8 9 10 11 12 13 14 15
"waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point FROM creature_movement");
barGoLink bar( result->GetRowCount() ); barGoLink bar( result->GetRowCount() );
do do
@ -92,6 +95,12 @@ void WaypointManager::Load()
Field *fields = result->Fetch(); Field *fields = result->Fetch();
uint32 point = fields[15].GetUInt32(); uint32 point = fields[15].GetUInt32();
uint32 id = fields[14].GetUInt32(); uint32 id = fields[14].GetUInt32();
if (!sObjectMgr.GetCreatureData(id))
{
sLog.outErrorDb("Table creature_movement references unknown creature %u. Skipping.", id);
continue;
}
WaypointPath &path = m_pathMap[id]; WaypointPath &path = m_pathMap[id];
// the cleanup queries make sure the following is true // the cleanup queries make sure the following is true
assert(point >= 1 && point <= path.size()); assert(point >= 1 && point <= path.size());
@ -141,6 +150,12 @@ void WaypointManager::Load()
} }
} }
if (be.spell && ! sSpellStore.LookupEntry(be.spell))
{
sLog.outErrorDb("Table creature_movement references unknown spellid %u. Skipping id %u with point %u.", be.spell, id, point);
be.spell = 0;
}
if (be.emote) if (be.emote)
{ {
if (!sEmotesStore.LookupEntry(be.emote)) if (!sEmotesStore.LookupEntry(be.emote))

View file

@ -1909,7 +1909,7 @@ bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
{ {
uint32 account = 0; uint32 account = 0;
if (mode == BAN_ACCOUNT) if (mode == BAN_ACCOUNT)
account = accmgr.GetId (nameOrIP); account = sAccountMgr.GetId (nameOrIP);
else if (mode == BAN_CHARACTER) else if (mode == BAN_CHARACTER)
account = sObjectMgr.GetPlayerAccountIdByPlayerName (nameOrIP); account = sObjectMgr.GetPlayerAccountIdByPlayerName (nameOrIP);

View file

@ -244,6 +244,11 @@ bool WorldSession::Update(uint32 /*diff*/)
LookupOpcodeName(packet->GetOpcode()), LookupOpcodeName(packet->GetOpcode()),
packet->GetOpcode()); packet->GetOpcode());
break; break;
case STATUS_UNHANDLED:
sLog.outDebug("SESSION: received not handled opcode %s (0x%.4X)",
LookupOpcodeName(packet->GetOpcode()),
packet->GetOpcode());
break;
} }
} }
catch(ByteBufferException &) catch(ByteBufferException &)

View file

@ -71,7 +71,7 @@ bool ChatHandler::HandleAccountDeleteCommand(const char* args)
return false; return false;
} }
uint32 account_id = accmgr.GetId(account_name); uint32 account_id = sAccountMgr.GetId(account_name);
if (!account_id) if (!account_id)
{ {
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
@ -85,7 +85,7 @@ bool ChatHandler::HandleAccountDeleteCommand(const char* args)
if(HasLowerSecurityAccount (NULL,account_id,true)) if(HasLowerSecurityAccount (NULL,account_id,true))
return false; return false;
AccountOpResult result = accmgr.DeleteAccount(account_id); AccountOpResult result = sAccountMgr.DeleteAccount(account_id);
switch(result) switch(result)
{ {
case AOR_OK: case AOR_OK:
@ -145,7 +145,7 @@ bool ChatHandler::HandleCharacterDeleteCommand(const char* args)
} }
std::string account_name; std::string account_name;
accmgr.GetName (account_id,account_name); sAccountMgr.GetName (account_id,account_name);
Player::DeleteFromDB(character_guid, account_id, true); Player::DeleteFromDB(character_guid, account_id, true);
PSendSysMessage(LANG_CHARACTER_DELETED,character_name.c_str(),GUID_LOPART(character_guid),account_name.c_str(), account_id); PSendSysMessage(LANG_CHARACTER_DELETED,character_name.c_str(),GUID_LOPART(character_guid),account_name.c_str(), account_id);
@ -223,7 +223,7 @@ bool ChatHandler::HandleAccountCreateCommand(const char* args)
std::string account_name = szAcc; std::string account_name = szAcc;
std::string password = szPassword; std::string password = szPassword;
AccountOpResult result = accmgr.CreateAccount(account_name, password); AccountOpResult result = sAccountMgr.CreateAccount(account_name, password);
switch(result) switch(result)
{ {
case AOR_OK: case AOR_OK:

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "8799" #define REVISION_NR "8812"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__ #ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__ #define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_8721_01_characters_guild" #define REVISION_DB_CHARACTERS "required_8721_01_characters_guild"
#define REVISION_DB_MANGOS "required_8777_02_mangos_gameobject" #define REVISION_DB_MANGOS "required_8803_02_mangos_playercreateinfo_action"
#define REVISION_DB_REALMD "required_8728_01_realmd_account" #define REVISION_DB_REALMD "required_8728_01_realmd_account"
#endif // __REVISION_SQL_H__ #endif // __REVISION_SQL_H__