[2] | 1 | /* |
---|
| 2 | * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> |
---|
| 3 | * |
---|
| 4 | * This program is free software; you can redistribute it and/or modify |
---|
| 5 | * it under the terms of the GNU General Public License as published by |
---|
| 6 | * the Free Software Foundation; either version 2 of the License, or |
---|
| 7 | * (at your option) any later version. |
---|
| 8 | * |
---|
| 9 | * This program is distributed in the hope that it will be useful, |
---|
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 12 | * GNU General Public License for more details. |
---|
| 13 | * |
---|
| 14 | * You should have received a copy of the GNU General Public License |
---|
| 15 | * along with this program; if not, write to the Free Software |
---|
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 17 | */ |
---|
| 18 | |
---|
| 19 | #include "SocialMgr.h" |
---|
| 20 | #include "Policies/SingletonImp.h" |
---|
| 21 | #include "Database/DatabaseEnv.h" |
---|
| 22 | #include "Opcodes.h" |
---|
| 23 | #include "WorldPacket.h" |
---|
| 24 | #include "WorldSession.h" |
---|
| 25 | #include "Player.h" |
---|
| 26 | #include "ObjectMgr.h" |
---|
| 27 | #include "World.h" |
---|
| 28 | #include "Util.h" |
---|
| 29 | |
---|
| 30 | INSTANTIATE_SINGLETON_1( SocialMgr ); |
---|
| 31 | |
---|
| 32 | PlayerSocial::PlayerSocial() |
---|
| 33 | { |
---|
| 34 | m_playerGUID = 0; |
---|
| 35 | } |
---|
| 36 | |
---|
| 37 | PlayerSocial::~PlayerSocial() |
---|
| 38 | { |
---|
| 39 | m_playerSocialMap.clear(); |
---|
| 40 | } |
---|
| 41 | |
---|
| 42 | bool PlayerSocial::AddToSocialList(uint32 friend_guid, bool ignore) |
---|
| 43 | { |
---|
| 44 | // prevent list (client-side) overflow |
---|
| 45 | if(m_playerSocialMap.size() >= (255-1)) |
---|
| 46 | return false; |
---|
| 47 | |
---|
| 48 | uint32 flag = SOCIAL_FLAG_FRIEND; |
---|
| 49 | if(ignore) |
---|
| 50 | flag = SOCIAL_FLAG_IGNORED; |
---|
| 51 | |
---|
| 52 | PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid); |
---|
| 53 | if(itr != m_playerSocialMap.end()) |
---|
| 54 | { |
---|
| 55 | CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid); |
---|
| 56 | m_playerSocialMap[friend_guid].Flags |= flag; |
---|
| 57 | } |
---|
| 58 | else |
---|
| 59 | { |
---|
| 60 | CharacterDatabase.PExecute("INSERT INTO character_social (guid, friend, flags) VALUES ('%u', '%u', '%u')", GetPlayerGUID(), friend_guid, flag); |
---|
| 61 | FriendInfo fi; |
---|
| 62 | fi.Flags |= flag; |
---|
| 63 | m_playerSocialMap[friend_guid] = fi; |
---|
| 64 | } |
---|
| 65 | return true; |
---|
| 66 | } |
---|
| 67 | |
---|
| 68 | void PlayerSocial::RemoveFromSocialList(uint32 friend_guid, bool ignore) |
---|
| 69 | { |
---|
| 70 | PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid); |
---|
| 71 | if(itr == m_playerSocialMap.end()) // not exist |
---|
| 72 | return; |
---|
| 73 | |
---|
| 74 | uint32 flag = SOCIAL_FLAG_FRIEND; |
---|
| 75 | if(ignore) |
---|
| 76 | flag = SOCIAL_FLAG_IGNORED; |
---|
| 77 | |
---|
| 78 | itr->second.Flags &= ~flag; |
---|
| 79 | if(itr->second.Flags == 0) |
---|
| 80 | { |
---|
| 81 | CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' AND friend = '%u'", GetPlayerGUID(), friend_guid); |
---|
| 82 | m_playerSocialMap.erase(itr); |
---|
| 83 | } |
---|
| 84 | else |
---|
| 85 | { |
---|
| 86 | CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags & ~%u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid); |
---|
| 87 | } |
---|
| 88 | } |
---|
| 89 | |
---|
| 90 | void PlayerSocial::SetFriendNote(uint32 friend_guid, std::string note) |
---|
| 91 | { |
---|
| 92 | PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid); |
---|
| 93 | if(itr == m_playerSocialMap.end()) // not exist |
---|
| 94 | return; |
---|
| 95 | |
---|
| 96 | utf8truncate(note,48); // DB and client size limitation |
---|
| 97 | |
---|
| 98 | CharacterDatabase.escape_string(note); |
---|
| 99 | CharacterDatabase.PExecute("UPDATE character_social SET note = '%s' WHERE guid = '%u' AND friend = '%u'", note.c_str(), GetPlayerGUID(), friend_guid); |
---|
| 100 | m_playerSocialMap[friend_guid].Note = note; |
---|
| 101 | } |
---|
| 102 | |
---|
| 103 | void PlayerSocial::SendSocialList() |
---|
| 104 | { |
---|
| 105 | Player *plr = objmgr.GetPlayer(GetPlayerGUID()); |
---|
| 106 | if(!plr) |
---|
| 107 | return; |
---|
| 108 | |
---|
| 109 | uint32 size = m_playerSocialMap.size(); |
---|
| 110 | |
---|
| 111 | WorldPacket data(SMSG_CONTACT_LIST, (4+4+size*25)); // just can guess size |
---|
| 112 | data << uint32(7); // unk flag (0x1, 0x2, 0x4), 0x7 if it include ignore list |
---|
| 113 | data << uint32(size); // friends count |
---|
| 114 | |
---|
| 115 | for(PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr) |
---|
| 116 | { |
---|
| 117 | sSocialMgr.GetFriendInfo(plr, itr->first, itr->second); |
---|
| 118 | |
---|
| 119 | data << uint64(itr->first); // player guid |
---|
| 120 | data << uint32(itr->second.Flags); // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?) |
---|
| 121 | data << itr->second.Note; // string note |
---|
| 122 | if(itr->second.Flags & SOCIAL_FLAG_FRIEND) // if IsFriend() |
---|
| 123 | { |
---|
| 124 | data << uint8(itr->second.Status); // online/offline/etc? |
---|
| 125 | if(itr->second.Status) // if online |
---|
| 126 | { |
---|
| 127 | data << uint32(itr->second.Area); // player area |
---|
| 128 | data << uint32(itr->second.Level); // player level |
---|
| 129 | data << uint32(itr->second.Class); // player class |
---|
| 130 | } |
---|
| 131 | } |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | plr->GetSession()->SendPacket(&data); |
---|
| 135 | sLog.outDebug("WORLD: Sent SMSG_CONTACT_LIST"); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | bool PlayerSocial::HasFriend(uint32 friend_guid) |
---|
| 139 | { |
---|
| 140 | PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid); |
---|
| 141 | if(itr != m_playerSocialMap.end()) |
---|
| 142 | return itr->second.Flags & SOCIAL_FLAG_FRIEND; |
---|
| 143 | return false; |
---|
| 144 | } |
---|
| 145 | |
---|
| 146 | bool PlayerSocial::HasIgnore(uint32 ignore_guid) |
---|
| 147 | { |
---|
| 148 | PlayerSocialMap::iterator itr = m_playerSocialMap.find(ignore_guid); |
---|
| 149 | if(itr != m_playerSocialMap.end()) |
---|
| 150 | return itr->second.Flags & SOCIAL_FLAG_IGNORED; |
---|
| 151 | return false; |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | SocialMgr::SocialMgr() |
---|
| 155 | { |
---|
| 156 | |
---|
| 157 | } |
---|
| 158 | |
---|
| 159 | SocialMgr::~SocialMgr() |
---|
| 160 | { |
---|
| 161 | |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | void SocialMgr::RemovePlayerSocial(uint32 guid) |
---|
| 165 | { |
---|
| 166 | SocialMap::iterator itr = m_socialMap.find(guid); |
---|
| 167 | if(itr != m_socialMap.end()) |
---|
| 168 | m_socialMap.erase(itr); |
---|
| 169 | } |
---|
| 170 | |
---|
| 171 | void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &friendInfo) |
---|
| 172 | { |
---|
| 173 | if(!player) |
---|
| 174 | return; |
---|
| 175 | |
---|
| 176 | Player *pFriend = ObjectAccessor::FindPlayer(friendGUID); |
---|
| 177 | |
---|
| 178 | uint32 team = player->GetTeam(); |
---|
| 179 | uint32 security = player->GetSession()->GetSecurity(); |
---|
| 180 | bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); |
---|
| 181 | bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || security > SEC_PLAYER; |
---|
| 182 | |
---|
| 183 | // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters |
---|
| 184 | // MODERATOR, GAME MASTER, ADMINISTRATOR can see all |
---|
| 185 | if( pFriend && pFriend->GetName() && |
---|
| 186 | ( security > SEC_PLAYER || |
---|
| 187 | ( pFriend->GetTeam() == team || allowTwoSideWhoList ) && |
---|
| 188 | ( pFriend->GetSession()->GetSecurity() == SEC_PLAYER || gmInWhoList && pFriend->IsVisibleGloballyFor(player) ))) |
---|
| 189 | { |
---|
| 190 | friendInfo.Status = FRIEND_STATUS_ONLINE; |
---|
| 191 | if(pFriend->isAFK()) |
---|
| 192 | friendInfo.Status = FRIEND_STATUS_AFK; |
---|
| 193 | if(pFriend->isDND()) |
---|
| 194 | friendInfo.Status = FRIEND_STATUS_DND; |
---|
| 195 | friendInfo.Area = pFriend->GetZoneId(); |
---|
| 196 | friendInfo.Level = pFriend->getLevel(); |
---|
| 197 | friendInfo.Class = pFriend->getClass(); |
---|
| 198 | } |
---|
| 199 | else |
---|
| 200 | { |
---|
| 201 | friendInfo.Status = FRIEND_STATUS_OFFLINE; |
---|
| 202 | friendInfo.Area = 0; |
---|
| 203 | friendInfo.Level = 0; |
---|
| 204 | friendInfo.Class = 0; |
---|
| 205 | } |
---|
| 206 | } |
---|
| 207 | |
---|
| 208 | void SocialMgr::MakeFriendStatusPacket(FriendsResult result, uint32 guid, WorldPacket *data) |
---|
| 209 | { |
---|
| 210 | data->Initialize(SMSG_FRIEND_STATUS, 5); |
---|
| 211 | *data << uint8(result); |
---|
| 212 | *data << uint64(guid); |
---|
| 213 | } |
---|
| 214 | |
---|
| 215 | void SocialMgr::SendFriendStatus(Player *player, FriendsResult result, uint32 friend_guid, std::string name, bool broadcast) |
---|
| 216 | { |
---|
| 217 | FriendInfo fi; |
---|
| 218 | |
---|
| 219 | WorldPacket data; |
---|
| 220 | MakeFriendStatusPacket(result, friend_guid, &data); |
---|
| 221 | switch(result) |
---|
| 222 | { |
---|
| 223 | case FRIEND_ONLINE: |
---|
| 224 | GetFriendInfo(player, friend_guid, fi); |
---|
| 225 | data << uint8(fi.Status); |
---|
| 226 | data << uint32(fi.Area); |
---|
| 227 | data << uint32(fi.Level); |
---|
| 228 | data << uint32(fi.Class); |
---|
| 229 | break; |
---|
| 230 | case FRIEND_ADDED_ONLINE: |
---|
| 231 | GetFriendInfo(player, friend_guid, fi); |
---|
| 232 | data << name; |
---|
| 233 | data << uint8(fi.Status); |
---|
| 234 | data << uint32(fi.Area); |
---|
| 235 | data << uint32(fi.Level); |
---|
| 236 | data << uint32(fi.Class); |
---|
| 237 | break; |
---|
| 238 | case FRIEND_ADDED_OFFLINE: |
---|
| 239 | data << name; |
---|
| 240 | break; |
---|
| 241 | } |
---|
| 242 | |
---|
| 243 | if(broadcast) |
---|
| 244 | BroadcastToFriendListers(player, &data); |
---|
| 245 | else |
---|
| 246 | player->GetSession()->SendPacket(&data); |
---|
| 247 | } |
---|
| 248 | |
---|
| 249 | void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet) |
---|
| 250 | { |
---|
| 251 | if(!player) |
---|
| 252 | return; |
---|
| 253 | |
---|
| 254 | uint32 team = player->GetTeam(); |
---|
| 255 | uint32 security = player->GetSession()->GetSecurity(); |
---|
| 256 | uint32 guid = player->GetGUIDLow(); |
---|
| 257 | bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST); |
---|
| 258 | bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); |
---|
| 259 | |
---|
| 260 | for(SocialMap::iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr) |
---|
| 261 | { |
---|
| 262 | PlayerSocialMap::iterator itr2 = itr->second.m_playerSocialMap.find(guid); |
---|
| 263 | if(itr2 != itr->second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND)) |
---|
| 264 | { |
---|
| 265 | Player *pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); |
---|
| 266 | |
---|
| 267 | // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters |
---|
| 268 | // MODERATOR, GAME MASTER, ADMINISTRATOR can see all |
---|
| 269 | if( pFriend && pFriend->IsInWorld() && |
---|
| 270 | ( pFriend->GetSession()->GetSecurity() > SEC_PLAYER || |
---|
| 271 | ( pFriend->GetTeam() == team || allowTwoSideWhoList ) && |
---|
| 272 | (security == SEC_PLAYER || gmInWhoList && player->IsVisibleGloballyFor(pFriend) ))) |
---|
| 273 | { |
---|
| 274 | pFriend->GetSession()->SendPacket(packet); |
---|
| 275 | } |
---|
| 276 | } |
---|
| 277 | } |
---|
| 278 | } |
---|
| 279 | |
---|
| 280 | PlayerSocial *SocialMgr::LoadFromDB(QueryResult *result, uint32 guid) |
---|
| 281 | { |
---|
| 282 | PlayerSocial *social = &m_socialMap[guid]; |
---|
| 283 | social->SetPlayerGUID(guid); |
---|
| 284 | |
---|
| 285 | if(!result) |
---|
| 286 | return social; |
---|
| 287 | |
---|
| 288 | uint32 friend_guid = 0; |
---|
| 289 | uint32 flags = 0; |
---|
| 290 | std::string note = ""; |
---|
| 291 | |
---|
| 292 | do |
---|
| 293 | { |
---|
| 294 | Field *fields = result->Fetch(); |
---|
| 295 | |
---|
| 296 | friend_guid = fields[0].GetUInt32(); |
---|
| 297 | flags = fields[1].GetUInt32(); |
---|
| 298 | note = fields[2].GetCppString(); |
---|
| 299 | |
---|
| 300 | social->m_playerSocialMap[friend_guid] = FriendInfo(flags, note); |
---|
| 301 | |
---|
| 302 | // prevent list (client-side) overflow |
---|
| 303 | if(social->m_playerSocialMap.size() >= 255) |
---|
| 304 | break; |
---|
| 305 | } |
---|
| 306 | while( result->NextRow() ); |
---|
| 307 | delete result; |
---|
| 308 | return social; |
---|
| 309 | } |
---|