From 6d9448dd7f9a83f1d5a878a7c9ec9655919cffba Mon Sep 17 00:00:00 2001 From: ApoC Date: Sun, 9 Aug 2009 10:59:22 +0200 Subject: [PATCH] [8339] Improved storing/restoring BG entry point * Introduced new table character_battleground_data * Entry point is now stored on BG enter event not join event * Entry point for dungeons is now correctly set to nearest graveyard (this prevent well known assert in GetInstance because of porting to already destroyed instance) * Teleporting from BG correctly restore mount state * Teleporting from BG correctly restore taxi flight (in multipath flight you will end up in nearest transition point on the route) Signed-off-by: ApoC --- sql/characters.sql | 38 ++- sql/updates/8339_01_characters_characters.sql | 9 + ...characters_character_battleground_data.sql | 17 ++ sql/updates/Makefile.am | 4 + src/game/BattleGround.cpp | 2 +- src/game/BattleGroundHandler.cpp | 14 +- src/game/CharacterHandler.cpp | 52 +--- src/game/Level1.cpp | 4 +- src/game/Player.cpp | 255 ++++++++++++++---- src/game/Player.h | 89 ++++-- src/mangosd/Master.cpp | 2 +- src/shared/revision_nr.h | 2 +- 12 files changed, 328 insertions(+), 160 deletions(-) create mode 100644 sql/updates/8339_01_characters_characters.sql create mode 100644 sql/updates/8339_02_characters_character_battleground_data.sql diff --git a/sql/characters.sql b/sql/characters.sql index 0858b64cb..0876bc6ef 100644 --- a/sql/characters.sql +++ b/sql/characters.sql @@ -21,7 +21,7 @@ DROP TABLE IF EXISTS `character_db_version`; CREATE TABLE `character_db_version` ( - `required_8104_01_characters` bit(1) default NULL + `required_8339_02_characters_character_battleground_data` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; -- @@ -232,13 +232,6 @@ CREATE TABLE `characters` ( `death_expire_time` bigint(20) unsigned NOT NULL default '0', `taxi_path` text, `arena_pending_points` int(10) UNSIGNED NOT NULL default '0', - `bgid` int(10) unsigned NOT NULL default '0', - `bgteam` int(10) unsigned NOT NULL default '0', - `bgmap` int(10) unsigned NOT NULL default '0', - `bgx` float NOT NULL default '0', - `bgy` float NOT NULL default '0', - `bgz` float NOT NULL default '0', - `bgo` float NOT NULL default '0', PRIMARY KEY (`guid`), KEY `idx_account` (`account`), KEY `idx_online` (`online`), @@ -346,6 +339,35 @@ LOCK TABLES `character_aura` WRITE; /*!40000 ALTER TABLE `character_aura` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `character_battleground_data` +-- + +DROP TABLE IF EXISTS `character_battleground_data`; +CREATE TABLE `character_battleground_data` ( + `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier', + `instance_id` int(11) unsigned NOT NULL default '0', + `team` int(11) unsigned NOT NULL default '0', + `join_x` float NOT NULL default '0', + `join_y` float NOT NULL default '0', + `join_z` float NOT NULL default '0', + `join_o` float NOT NULL default '0', + `join_map` int(11) NOT NULL default '0', + `taxi_start` int(11) NOT NULL default '0', + `taxi_end` int(11) NOT NULL default '0', + `mount_spell` int(11) NOT NULL default '0', + PRIMARY KEY (`guid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; + +-- +-- Dumping data for table `character_battleground_data` +-- + +LOCK TABLES `character_battleground_data` WRITE; +/*!40000 ALTER TABLE `character_battleground_data` DISABLE KEYS */; +/*!40000 ALTER TABLE `character_battleground_data` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `character_declinedname` -- diff --git a/sql/updates/8339_01_characters_characters.sql b/sql/updates/8339_01_characters_characters.sql new file mode 100644 index 000000000..54cc217a2 --- /dev/null +++ b/sql/updates/8339_01_characters_characters.sql @@ -0,0 +1,9 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_8104_01_characters required_8339_01_characters_characters bit; + +ALTER TABLE characters DROP COLUMN bgid; +ALTER TABLE characters DROP COLUMN bgteam; +ALTER TABLE characters DROP COLUMN bgmap; +ALTER TABLE characters DROP COLUMN bgx; +ALTER TABLE characters DROP COLUMN bgy; +ALTER TABLE characters DROP COLUMN bgz; +ALTER TABLE characters DROP COLUMN bgo; diff --git a/sql/updates/8339_02_characters_character_battleground_data.sql b/sql/updates/8339_02_characters_character_battleground_data.sql new file mode 100644 index 000000000..e735c391f --- /dev/null +++ b/sql/updates/8339_02_characters_character_battleground_data.sql @@ -0,0 +1,17 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_8339_01_characters_characters required_8339_02_characters_character_battleground_data bit; + +DROP TABLE IF EXISTS `character_battleground_data`; +CREATE TABLE `character_battleground_data` ( + `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier', + `instance_id` int(11) unsigned NOT NULL default '0', + `team` int(11) unsigned NOT NULL default '0', + `join_x` float NOT NULL default '0', + `join_y` float NOT NULL default '0', + `join_z` float NOT NULL default '0', + `join_o` float NOT NULL default '0', + `join_map` int(11) NOT NULL default '0', + `taxi_start` int(11) NOT NULL default '0', + `taxi_end` int(11) NOT NULL default '0', + `mount_spell` int(11) NOT NULL default '0', + PRIMARY KEY (`guid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 681d4975e..20d68977f 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -77,6 +77,8 @@ pkgdata_DATA = \ 8294_01_mangos_playercreateinfo_action.sql \ 8310_01_mangos_spell_proc_event.sql \ 8332_01_realmd_realmcharacters.sql \ + 8339_01_characters_characters.sql \ + 8339_02_characters_character_battleground_data.sql \ README ## Additional files to include when running 'make dist' @@ -134,4 +136,6 @@ EXTRA_DIST = \ 8294_01_mangos_playercreateinfo_action.sql \ 8310_01_mangos_spell_proc_event.sql \ 8332_01_realmd_realmcharacters.sql \ + 8339_01_characters_characters.sql \ + 8339_02_characters_character_battleground_data.sql \ README diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 97cd09ab1..446b2aac2 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -1043,7 +1043,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac plr->SetBGTeam(0); if (Transport) - plr->TeleportTo(plr->GetBattleGroundEntryPoint()); + plr->TeleportToBGEntryPoint(); sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName()); } diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index a24ff1bdc..152221e2f 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -161,9 +161,6 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data ) uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue - // store entry point coords - member->SetBattleGroundEntryPoint(member->GetMapId(),member->GetPositionX(),member->GetPositionY(),member->GetPositionZ(),member->GetOrientation()); - WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); @@ -179,8 +176,6 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data ) { // already checked if queueSlot is valid, now just get it uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); - // store entry point coords - _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue) @@ -435,6 +430,9 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data ) case 1: // port to battleground if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) return; // cheating? + + _player->SetBattleGroundEntryPoint(); + // resurrect the player if (!_player->isAlive()) { @@ -751,9 +749,6 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data ) uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue - // store entry point coords (same as leader entry point) - member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); - WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); @@ -771,9 +766,6 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data ) { uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); - // store entry point coords - _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); - WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index ce10794bc..98d6d068e 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -59,7 +59,7 @@ bool LoginQueryHolder::Initialize() // NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure. // !!! NOTE: including unused `zone`,`online` - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid)); @@ -82,6 +82,7 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS,"SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, "SELECT instance_id, team, join_x, join_y, join_z, join_o, join_map, taxi_start, taxi_end, mount_spell FROM character_battleground_data WHERE guid = '%u'", GUID_LOPART(m_guid)); return res; } @@ -745,54 +746,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) pCurrChar->SetMovement(MOVE_WATER_WALK); } - if(uint32 sourceNode = pCurrChar->m_taxi.GetTaxiSource()) - { - sLog.outDebug( "WORLD: Restart character %u taxi flight", pCurrChar->GetGUIDLow() ); - - uint32 mountDisplayId = objmgr.GetTaxiMountDisplayId(sourceNode, pCurrChar->GetTeam(),true); - uint32 path = pCurrChar->m_taxi.GetCurrentTaxiPath(); - - // search appropriate start path node - uint32 startNode = 0; - - TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path]; - - float distPrev = MAP_SIZE*MAP_SIZE; - float distNext = - (nodeList[0].x-pCurrChar->GetPositionX())*(nodeList[0].x-pCurrChar->GetPositionX())+ - (nodeList[0].y-pCurrChar->GetPositionY())*(nodeList[0].y-pCurrChar->GetPositionY())+ - (nodeList[0].z-pCurrChar->GetPositionZ())*(nodeList[0].z-pCurrChar->GetPositionZ()); - - for(uint32 i = 1; i < nodeList.size(); ++i) - { - TaxiPathNode const& node = nodeList[i]; - TaxiPathNode const& prevNode = nodeList[i-1]; - - // skip nodes at another map - if(node.mapid != pCurrChar->GetMapId()) - continue; - - distPrev = distNext; - - distNext = - (node.x-pCurrChar->GetPositionX())*(node.x-pCurrChar->GetPositionX())+ - (node.y-pCurrChar->GetPositionY())*(node.y-pCurrChar->GetPositionY())+ - (node.z-pCurrChar->GetPositionZ())*(node.z-pCurrChar->GetPositionZ()); - - float distNodes = - (node.x-prevNode.x)*(node.x-prevNode.x)+ - (node.y-prevNode.y)*(node.y-prevNode.y)+ - (node.z-prevNode.z)*(node.z-prevNode.z); - - if(distNext + distPrev < distNodes) - { - startNode = i; - break; - } - } - - SendDoFlight( mountDisplayId, path, startNode ); - } + pCurrChar->ContinueTaxiFlight(); // reset for all pets before pet loading if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index ba089c72d..19e8225a7 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -393,7 +393,7 @@ bool ChatHandler::HandleNamegoCommand(const char* args) // when porting out from the bg, it will be reset to 0 target->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId(), m_session->GetPlayer()->GetBattleGroundTypeId()); // remember current position as entry point for return at bg end teleportation - target->SetBattleGroundEntryPoint(target->GetMapId(),target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(),target->GetOrientation()); + target->SetBattleGroundEntryPoint(); } else if (pMap->IsDungeon()) { @@ -507,7 +507,7 @@ bool ChatHandler::HandleGonameCommand(const char* args) // when porting out from the bg, it will be reset to 0 _player->SetBattleGroundId(target->GetBattleGroundId(), target->GetBattleGroundTypeId()); // remember current position as entry point for return at bg end teleportation - _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); + _player->SetBattleGroundEntryPoint(); } else if(cMap->IsDungeon()) { diff --git a/src/game/Player.cpp b/src/game/Player.cpp index c8f78cc1e..edc2aae3d 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -370,14 +370,11 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_DetectInvTimer = 1*IN_MILISECONDS; - m_bgBattleGroundID = 0; - m_bgTypeID = BATTLEGROUND_TYPE_NONE; for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j) { m_bgBattleGroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; m_bgBattleGroundQueueID[j].invitedToInstance = 0; } - m_bgTeam = 0; m_logintime = time(NULL); m_Last_tick = m_logintime; @@ -457,7 +454,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_mover = this; m_miniPet = 0; - m_bgAfkReportedTimer = 0; m_contestedPvPTimer = 0; m_declinedname = NULL; @@ -1774,6 +1770,13 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati return true; } +bool Player::TeleportToBGEntryPoint() +{ + ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE); + ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE); + return TeleportTo(m_bgData.joinPos); +} + void Player::ProcessDelayedOperations() { if(m_DelayedOperations == 0) @@ -1809,18 +1812,31 @@ void Player::ProcessDelayedOperations() CastSpell(this, 26013, true); // Deserter } + if (m_DelayedOperations & DELAYED_BG_MOUNT_RESTORE) + { + if (m_bgData.mountSpell) + { + CastSpell(this, m_bgData.mountSpell, true); + m_bgData.mountSpell = 0; + } + } + + if (m_DelayedOperations & DELAYED_BG_TAXI_RESTORE) + { + if (m_bgData.HasTaxiPath()) + { + m_taxi.AddTaxiDestination(m_bgData.taxiPath[0]); + m_taxi.AddTaxiDestination(m_bgData.taxiPath[1]); + m_bgData.ClearTaxiPath(); + + ContinueTaxiFlight(); + } + } + //we have executed ALL delayed ops, so clear the flag m_DelayedOperations = 0; } -void Player::ScheduleDelayedOperation(uint32 operation) -{ - if(operation >= DELAYED_END) - return; - - m_DelayedOperations |= operation; -} - void Player::AddToWorld() { ///- Do not add/remove the player from the object storage @@ -13934,6 +13950,28 @@ void Player::_LoadEquipmentSets(QueryResult *result) delete result; } +void Player::_LoadBGData(QueryResult* result) +{ + if (!result) + return; + + // Expecting only one row + Field *fields = result->Fetch(); + /* bgInstanceID, bgTeam, x, y, z, o, map, taxi[0], taxi[1], mountSpell */ + m_bgData.bgInstanceID = fields[0].GetUInt32(); + m_bgData.bgTeam = fields[1].GetUInt32(); + m_bgData.joinPos = WorldLocation(fields[6].GetUInt32(), // Map + fields[2].GetFloat(), // X + fields[3].GetFloat(), // Y + fields[4].GetFloat(), // Z + fields[5].GetFloat()); // Orientation + m_bgData.taxiPath[0] = fields[7].GetUInt32(); + m_bgData.taxiPath[1] = fields[8].GetUInt32(); + m_bgData.mountSpell = fields[9].GetUInt32(); + + delete result; +} + bool Player::LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid) { QueryResult *result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,taxi_path FROM characters WHERE guid = '%u'",GUID_LOPART(guid)); @@ -14005,8 +14043,8 @@ float Player::GetFloatValueFromDB(uint16 index, uint64 guid) bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) { - //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 - //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid); + //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 + //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points FROM characters WHERE guid = '%u'", guid); QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM); if(!result) @@ -14149,31 +14187,22 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) m_movementInfo.t_o = 0.0f; } - uint32 bgid = fields[41].GetUInt32(); - uint32 bgteam = fields[42].GetUInt32(); + _LoadBGData(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBGDATA)); - if(bgid) //saved in BattleGround + if(m_bgData.bgInstanceID) //saved in BattleGround { - SetBattleGroundEntryPoint(fields[43].GetUInt32(),fields[44].GetFloat(),fields[45].GetFloat(),fields[46].GetFloat(),fields[47].GetFloat()); - - // check entry point and fix to homebind if need - MapEntry const* mapEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid); - if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint)) - SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f); - - BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid, BATTLEGROUND_TYPE_NONE); + BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(m_bgData.bgInstanceID, BATTLEGROUND_TYPE_NONE); if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID())) { BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType()); AddBattleGroundQueueId(bgQueueTypeId); - SetBattleGroundId(currentBg->GetInstanceID(), currentBg->GetTypeID()); - SetBGTeam(bgteam); + m_bgData.bgTypeID = currentBg->GetTypeID(); //join player to battleground group currentBg->EventPlayerLoggedIn(this, GetGUID()); - currentBg->AddOrSetPlayerToCorrectBgGroup(this, GetGUID(), bgteam); + currentBg->AddOrSetPlayerToCorrectBgGroup(this, GetGUID(), m_bgData.bgTeam); SetInviteForBattleGroundQueueType(bgQueueTypeId,currentBg->GetInstanceID()); } @@ -14182,7 +14211,6 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) const WorldLocation& _loc = GetBattleGroundEntryPoint(); SetLocationMapId(_loc.mapid); Relocate(_loc.coord_x, _loc.coord_y, _loc.coord_z, _loc.orientation); - //RemoveArenaAuras(true); } } else @@ -14192,14 +14220,9 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // player can have current coordinates in to BG/Arean map, fix this if(!mapEntry || mapEntry->IsBattleGroundOrArena()) { - // return to BG master - SetLocationMapId(fields[43].GetUInt32()); - Relocate(fields[44].GetFloat(),fields[45].GetFloat(),fields[46].GetFloat(),fields[47].GetFloat()); - - // check entry point and fix to homebind if need - mapEntry = sMapStore.LookupEntry(GetMapId()); - if(!mapEntry || mapEntry->IsBattleGroundOrArena() || !IsPositionValid()) - RelocateToHomebind(); + const WorldLocation& _loc = GetBattleGroundEntryPoint(); + SetLocationMapId(_loc.mapid); + Relocate(_loc.coord_x, _loc.coord_y, _loc.coord_z, _loc.orientation); } } @@ -14447,7 +14470,13 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) } // Not finish taxi flight path - if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam())) + if(m_bgData.HasTaxiPath()) + { + m_taxi.ClearTaxiDestinations(); + for (int i = 0; i < 2; ++i) + m_taxi.AddTaxiDestination(m_bgData.taxiPath[i]); + } + else if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam())) { // problems with taxi path loading TaxiNodesEntry const* nodeEntry = NULL; @@ -14473,7 +14502,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) m_taxi.ClearTaxiDestinations(); } - else if(uint32 node_id = m_taxi.GetTaxiSource()) + + if(uint32 node_id = m_taxi.GetTaxiSource()) { // save source node as recall coord to prevent recall and fall from sky TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id); @@ -15519,7 +15549,7 @@ void Player::SaveToDB() "taximask, online, cinematic, " "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, " "trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, " - "death_expire_time, taxi_path, arena_pending_points, bgid, bgteam, bgmap, bgx, bgy, bgz, bgo) VALUES (" + "death_expire_time, taxi_path, arena_pending_points) VALUES (" << GetGUIDLow() << ", " << GetSession()->GetAccountId() << ", '" << sql_name << "', " @@ -15598,14 +15628,7 @@ void Player::SaveToDB() ss << (uint64)m_deathExpireTime << ", '"; ss << m_taxi.SaveTaxiDestinationsToString() << "', "; - ss << "'0', "; // arena_pending_points - ss << GetBattleGroundId() << ", "; - ss << GetBGTeam() << ", "; - ss << m_bgEntryPoint.mapid << ", " - << finiteAlways(m_bgEntryPoint.coord_x) << ", " - << finiteAlways(m_bgEntryPoint.coord_y) << ", " - << finiteAlways(m_bgEntryPoint.coord_z) << ", " - << finiteAlways(m_bgEntryPoint.orientation); + ss << "'0' "; // arena_pending_points ss << ")"; CharacterDatabase.Execute( ss.str().c_str() ); @@ -15613,6 +15636,7 @@ void Player::SaveToDB() if(m_mailsUpdated) //save mails only when needed _SaveMail(); + _SaveBGData(); _SaveInventory(); _SaveQuestStatus(); _SaveDailyQuestStatus(); @@ -16192,10 +16216,10 @@ void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) ///checks the 15 afk reports per 5 minutes limit void Player::UpdateAfkReport(time_t currTime) { - if(m_bgAfkReportedTimer <= currTime) + if(m_bgData.bgAfkReportedTimer <= currTime) { - m_bgAfkReportedCount = 0; - m_bgAfkReportedTimer = currTime+5*MINUTE; + m_bgData.bgAfkReportedCount = 0; + m_bgData.bgAfkReportedTimer = currTime+5*MINUTE; } } @@ -17017,6 +17041,59 @@ bool Player::ActivateTaxiPathTo( uint32 taxi_path_id, uint32 spellid /*= 0*/ ) return ActivateTaxiPathTo(nodes,NULL,spellid); } +void Player::ContinueTaxiFlight() +{ + uint32 sourceNode = m_taxi.GetTaxiSource(); + if (!sourceNode) + return; + + sLog.outDebug( "WORLD: Restart character %u taxi flight", GetGUIDLow() ); + + uint32 mountDisplayId = objmgr.GetTaxiMountDisplayId(sourceNode, GetTeam(),true); + uint32 path = m_taxi.GetCurrentTaxiPath(); + + // search appropriate start path node + uint32 startNode = 0; + + TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path]; + + float distPrev = MAP_SIZE*MAP_SIZE; + float distNext = + (nodeList[0].x-GetPositionX())*(nodeList[0].x-GetPositionX())+ + (nodeList[0].y-GetPositionY())*(nodeList[0].y-GetPositionY())+ + (nodeList[0].z-GetPositionZ())*(nodeList[0].z-GetPositionZ()); + + for(uint32 i = 1; i < nodeList.size(); ++i) + { + TaxiPathNode const& node = nodeList[i]; + TaxiPathNode const& prevNode = nodeList[i-1]; + + // skip nodes at another map + if(node.mapid != GetMapId()) + continue; + + distPrev = distNext; + + distNext = + (node.x-GetPositionX())*(node.x-GetPositionX())+ + (node.y-GetPositionY())*(node.y-GetPositionY())+ + (node.z-GetPositionZ())*(node.z-GetPositionZ()); + + float distNodes = + (node.x-prevNode.x)*(node.x-prevNode.x)+ + (node.y-prevNode.y)*(node.y-prevNode.y)+ + (node.z-prevNode.z)*(node.z-prevNode.z); + + if(distNext + distPrev < distNodes) + { + startNode = i; + break; + } + } + + GetSession()->SendDoFlight(mountDisplayId, path, startNode); +} + void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ) { // last check 2.0.10 @@ -17698,6 +17775,56 @@ void Player::ToggleMetaGemsActive(uint8 exceptslot, bool apply) } } +void Player::SetBattleGroundEntryPoint() +{ + // Taxi path store + if (!m_taxi.empty()) + { + m_bgData.mountSpell = 0; + m_bgData.taxiPath[0] = m_taxi.GetTaxiSource(); + m_bgData.taxiPath[1] = m_taxi.GetTaxiDestination(); + + // On taxi we don't need check for dungeon + m_bgData.joinPos = WorldLocation(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); + return; + } + else + { + m_bgData.ClearTaxiPath(); + + // Mount spell id storing + if (IsMounted()) + { + AuraList const& auras = GetAurasByType(SPELL_AURA_MOUNTED); + if (!auras.empty()) + m_bgData.mountSpell = (*auras.begin())->GetId(); + } + else + m_bgData.mountSpell = 0; + + // If map is dungeon find linked graveyard + if(GetMap()->IsDungeon()) + { + if (const WorldSafeLocsEntry* entry = objmgr.GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam())) + { + m_bgData.joinPos = WorldLocation(entry->map_id, entry->x, entry->y, entry->z, 0.0f); + return; + } + else + sLog.outError("SetBattleGroundEntryPoint: Dungeon map %u has no linked graveyard, setting home location as entry point.", GetMapId()); + } + // If new entry point is not BG or arena set it + else if (!GetMap()->IsBattleGroundOrArena()) + { + m_bgData.joinPos = WorldLocation(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); + return; + } + } + + // In error cases use homebind position + m_bgData.joinPos = WorldLocation(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, 0.0f); +} + void Player::LeaveBattleground(bool teleportToEntryPoint) { if(BattleGround *bg = GetBattleGround()) @@ -17734,9 +17861,9 @@ bool Player::CanJoinToBattleground() const bool Player::CanReportAfkDueToLimit() { // a player can complain about 15 people per 5 minutes - if(m_bgAfkReportedCount >= 15) + if(m_bgData.bgAfkReportedCount++ >= 15) return false; - ++m_bgAfkReportedCount; + return true; } @@ -17748,15 +17875,15 @@ void Player::ReportedAfkBy(Player* reporter) return; // check if player has 'Idle' or 'Inactive' debuff - if(m_bgAfkReporter.find(reporter->GetGUIDLow())==m_bgAfkReporter.end() && !HasAura(43680,0) && !HasAura(43681,0) && reporter->CanReportAfkDueToLimit()) + if(m_bgData.bgAfkReporter.find(reporter->GetGUIDLow())==m_bgData.bgAfkReporter.end() && !HasAura(43680,0) && !HasAura(43681,0) && reporter->CanReportAfkDueToLimit()) { - m_bgAfkReporter.insert(reporter->GetGUIDLow()); + m_bgData.bgAfkReporter.insert(reporter->GetGUIDLow()); // 3 players have to complain to apply debuff - if(m_bgAfkReporter.size() >= 3) + if(m_bgData.bgAfkReporter.size() >= 3) { // cast 'Idle' spell CastSpell(this, 43680, true); - m_bgAfkReporter.clear(); + m_bgData.bgAfkReporter.clear(); } } } @@ -18389,7 +18516,7 @@ BattleGround* Player::GetBattleGround() const if(GetBattleGroundId()==0) return NULL; - return sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgTypeID); + return sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgData.bgTypeID); } bool Player::InArena() const @@ -20375,6 +20502,18 @@ void Player::_SaveEquipmentSets() } } +void Player::_SaveBGData() +{ + CharacterDatabase.PExecute("DELETE FROM character_battleground_data WHERE guid='%u'", GetGUIDLow()); + if (m_bgData.bgInstanceID) + { + /* guid, bgInstanceID, bgTeam, x, y, z, o, map, taxi[0], taxi[1], mountSpell */ + CharacterDatabase.PExecute("INSERT INTO character_battleground_data VALUES ('%u', '%u', '%u', '%f', '%f', '%f', '%f', '%u', '%u', '%u', '%u')", + GetGUIDLow(), m_bgData.bgInstanceID, m_bgData.bgTeam, m_bgData.joinPos.coord_x, m_bgData.joinPos.coord_y, m_bgData.joinPos.coord_z, + m_bgData.joinPos.orientation, m_bgData.joinPos.mapid, m_bgData.taxiPath[0], m_bgData.taxiPath[1], m_bgData.mountSpell); + } +} + void Player::DeleteEquipmentSet(uint64 setGuid) { for(EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end(); ++itr) diff --git a/src/game/Player.h b/src/game/Player.h index 40f5e9347..659c8465b 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -866,14 +866,17 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS = 18, PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS = 19, PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS = 20, - MAX_PLAYER_LOGIN_QUERY = 21 + PLAYER_LOGIN_QUERY_LOADBGDATA = 21, + MAX_PLAYER_LOGIN_QUERY = 22 }; enum PlayerDelayedOperations { - DELAYED_SAVE_PLAYER = 1, - DELAYED_RESURRECT_PLAYER = 2, - DELAYED_SPELL_CAST_DESERTER = 4, + DELAYED_SAVE_PLAYER = 0x01, + DELAYED_RESURRECT_PLAYER = 0x02, + DELAYED_SPELL_CAST_DESERTER = 0x04, + DELAYED_BG_MOUNT_RESTORE = 0x08, ///< Flag to restore mount state after teleport from BG + DELAYED_BG_TAXI_RESTORE = 0x10, ///< Flag to restore taxi state after teleport from BG DELAYED_END }; @@ -944,6 +947,35 @@ class MANGOS_DLL_SPEC PlayerTaxi std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi); +class Player; + +/// Holder for BattleGround data +struct BGData +{ + BGData() : bgInstanceID(0), bgTypeID(BATTLEGROUND_TYPE_NONE), bgAfkReportedCount(0), bgAfkReportedTimer(0), + bgTeam(0), mountSpell(0) { ClearTaxiPath(); } + + + uint32 bgInstanceID; ///< This variable is set to bg->m_InstanceID, + /// when player is teleported to BG - (it is battleground's GUID) + BattleGroundTypeId bgTypeID; + + std::set bgAfkReporter; + uint8 bgAfkReportedCount; + time_t bgAfkReportedTimer; + + uint32 bgTeam; ///< What side the player will be added to + + + uint32 mountSpell; + uint32 taxiPath[2]; + + WorldLocation joinPos; ///< From where player entered BG + + void ClearTaxiPath() { taxiPath[0] = taxiPath[1] = 0; } + bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; } +}; + class MANGOS_DLL_SPEC Player : public Unit { friend class WorldSession; @@ -968,6 +1000,8 @@ class MANGOS_DLL_SPEC Player : public Unit return TeleportTo(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation, options); } + bool TeleportToBGEntryPoint(); + void SetSummonPoint(uint32 mapid, float x, float y, float z) { m_summon_expire = time(NULL) + MAX_PLAYER_SUMMON_DELAY; @@ -1015,6 +1049,7 @@ class MANGOS_DLL_SPEC Player : public Unit bool ActivateTaxiPathTo(std::vector const& nodes, Creature* npc = NULL, uint32 spellid = 0); bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0); // mount_id can be used in scripting calls + void ContinueTaxiFlight(); bool isAcceptTickets() const { return GetSession()->GetSecurity() >= SEC_GAMEMASTER && (m_ExtraFlags & PLAYER_EXTRA_GM_ACCEPT_TICKETS); } void SetAcceptTicket(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_GM_ACCEPT_TICKETS; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_ACCEPT_TICKETS; } bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; } @@ -1893,10 +1928,10 @@ class MANGOS_DLL_SPEC Player : public Unit /*** BATTLEGROUND SYSTEM ***/ /*********************************************************/ - bool InBattleGround() const { return m_bgBattleGroundID != 0; } + bool InBattleGround() const { return m_bgData.bgInstanceID != 0; } bool InArena() const; - uint32 GetBattleGroundId() const { return m_bgBattleGroundID; } - BattleGroundTypeId GetBattleGroundTypeId() const { return m_bgTypeID; } + uint32 GetBattleGroundId() const { return m_bgData.bgInstanceID; } + BattleGroundTypeId GetBattleGroundTypeId() const { return m_bgData.bgTypeID; } BattleGround* GetBattleGround() const; @@ -1932,8 +1967,8 @@ class MANGOS_DLL_SPEC Player : public Unit void SetBattleGroundId(uint32 val, BattleGroundTypeId bgTypeId) { - m_bgBattleGroundID = val; - m_bgTypeID = bgTypeId; + m_bgData.bgInstanceID = val; + m_bgData.bgTypeID = bgTypeId; } uint32 AddBattleGroundQueueId(BattleGroundQueueTypeId val) { @@ -1980,20 +2015,17 @@ class MANGOS_DLL_SPEC Player : public Unit return true; return false; } - WorldLocation const& GetBattleGroundEntryPoint() const { return m_bgEntryPoint; } - void SetBattleGroundEntryPoint(uint32 Map, float PosX, float PosY, float PosZ, float PosO ) - { - m_bgEntryPoint = WorldLocation(Map,PosX,PosY,PosZ,PosO); - } + WorldLocation const& GetBattleGroundEntryPoint() const { return m_bgData.joinPos; } + void SetBattleGroundEntryPoint(); - void SetBGTeam(uint32 team) { m_bgTeam = team; } - uint32 GetBGTeam() const { return m_bgTeam ? m_bgTeam : GetTeam(); } + void SetBGTeam(uint32 team) { m_bgData.bgTeam = team; } + uint32 GetBGTeam() const { return m_bgData.bgTeam ? m_bgData.bgTeam : GetTeam(); } void LeaveBattleground(bool teleportToEntryPoint = true); bool CanJoinToBattleground() const; bool CanReportAfkDueToLimit(); void ReportedAfkBy(Player* reporter); - void ClearAfkReports() { m_bgAfkReporter.clear(); } + void ClearAfkReports() { m_bgData.bgAfkReporter.clear(); } bool GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const; bool CanUseBattleGroundObject(); @@ -2193,13 +2225,12 @@ class MANGOS_DLL_SPEC Player : public Unit bool canSeeSpellClickOn(Creature const* creature) const; protected: + uint32 m_contestedPvPTimer; + /*********************************************************/ /*** BATTLEGROUND SYSTEM ***/ /*********************************************************/ - /* this variable is set to bg->m_InstanceID, when player is teleported to BG - (it is battleground's GUID)*/ - uint32 m_bgBattleGroundID; - BattleGroundTypeId m_bgTypeID; /* this is an array of BG queues (BgTypeIDs) in which is player */ @@ -2208,15 +2239,9 @@ class MANGOS_DLL_SPEC Player : public Unit BattleGroundQueueTypeId bgQueueTypeId; uint32 invitedToInstance; }; + BgBattleGroundQueueID_Rec m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES]; - WorldLocation m_bgEntryPoint; - - std::set m_bgAfkReporter; - uint8 m_bgAfkReportedCount; - time_t m_bgAfkReportedTimer; - uint32 m_contestedPvPTimer; - - uint32 m_bgTeam; // what side the player will be added to + BGData m_bgData; /*********************************************************/ /*** QUEST SYSTEM ***/ @@ -2249,6 +2274,7 @@ class MANGOS_DLL_SPEC Player : public Unit void _LoadDeclinedNames(QueryResult *result); void _LoadArenaTeamInfo(QueryResult *result); void _LoadEquipmentSets(QueryResult *result); + void _LoadBGData(QueryResult* result); /*********************************************************/ /*** SAVE SYSTEM ***/ @@ -2262,6 +2288,7 @@ class MANGOS_DLL_SPEC Player : public Unit void _SaveDailyQuestStatus(); void _SaveSpells(); void _SaveEquipmentSets(); + void _SaveBGData(); void _SetCreateBits(UpdateMask *updateMask, Player *target) const; void _SetUpdateBits(UpdateMask *updateMask, Player *target) const; @@ -2430,7 +2457,11 @@ class MANGOS_DLL_SPEC Player : public Unit bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; } void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; } - void ScheduleDelayedOperation(uint32 operation); + void ScheduleDelayedOperation(uint32 operation) + { + if(operation < DELAYED_END) + m_DelayedOperations |= operation; + } GridReference m_gridRef; MapReference m_mapRef; diff --git a/src/mangosd/Master.cpp b/src/mangosd/Master.cpp index e29702de7..996cade19 100644 --- a/src/mangosd/Master.cpp +++ b/src/mangosd/Master.cpp @@ -476,7 +476,7 @@ void Master::clearOnlineAccounts() CharacterDatabase.Execute("UPDATE characters SET online = 0 WHERE online<>0"); // Battleground instance ids reset at server restart - CharacterDatabase.Execute("UPDATE characters SET bgid = 0 WHERE bgid<>0"); + CharacterDatabase.Execute("UPDATE character_battleground_data SET instance_id = 0"); } /// Handle termination signals diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 31a74868a..8a7d5a04f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8338" + #define REVISION_NR "8339" #endif // __REVISION_NR_H__