2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
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.
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.
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
19 #include "SocialMgr.h"
20 #include "Policies/SingletonImp.h"
21 #include "Database/DatabaseEnv.h"
23 #include "WorldPacket.h"
24 #include "WorldSession.h"
26 #include "ObjectMgr.h"
30 INSTANTIATE_SINGLETON_1( SocialMgr
);
32 PlayerSocial::PlayerSocial()
37 PlayerSocial::~PlayerSocial()
39 m_playerSocialMap
.clear();
42 uint32
PlayerSocial::GetNumberOfSocialsWithFlag(SocialFlag flag
)
45 for(PlayerSocialMap::iterator itr
= m_playerSocialMap
.begin(); itr
!= m_playerSocialMap
.end(); ++itr
)
47 if(itr
->second
.Flags
& flag
)
53 bool PlayerSocial::AddToSocialList(uint32 friend_guid
, bool ignore
)
55 // check client limits
58 if(GetNumberOfSocialsWithFlag(SOCIAL_FLAG_IGNORED
) >= SOCIALMGR_IGNORE_LIMIT
)
63 if(GetNumberOfSocialsWithFlag(SOCIAL_FLAG_FRIEND
) >= SOCIALMGR_FRIEND_LIMIT
)
67 uint32 flag
= SOCIAL_FLAG_FRIEND
;
69 flag
= SOCIAL_FLAG_IGNORED
;
71 PlayerSocialMap::iterator itr
= m_playerSocialMap
.find(friend_guid
);
72 if(itr
!= m_playerSocialMap
.end())
74 CharacterDatabase
.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag
, GetPlayerGUID(), friend_guid
);
75 m_playerSocialMap
[friend_guid
].Flags
|= flag
;
79 CharacterDatabase
.PExecute("INSERT INTO character_social (guid, friend, flags) VALUES ('%u', '%u', '%u')", GetPlayerGUID(), friend_guid
, flag
);
82 m_playerSocialMap
[friend_guid
] = fi
;
87 void PlayerSocial::RemoveFromSocialList(uint32 friend_guid
, bool ignore
)
89 PlayerSocialMap::iterator itr
= m_playerSocialMap
.find(friend_guid
);
90 if(itr
== m_playerSocialMap
.end()) // not exist
93 uint32 flag
= SOCIAL_FLAG_FRIEND
;
95 flag
= SOCIAL_FLAG_IGNORED
;
97 itr
->second
.Flags
&= ~flag
;
98 if(itr
->second
.Flags
== 0)
100 CharacterDatabase
.PExecute("DELETE FROM character_social WHERE guid = '%u' AND friend = '%u'", GetPlayerGUID(), friend_guid
);
101 m_playerSocialMap
.erase(itr
);
105 CharacterDatabase
.PExecute("UPDATE character_social SET flags = (flags & ~%u) WHERE guid = '%u' AND friend = '%u'", flag
, GetPlayerGUID(), friend_guid
);
109 void PlayerSocial::SetFriendNote(uint32 friend_guid
, std::string note
)
111 PlayerSocialMap::iterator itr
= m_playerSocialMap
.find(friend_guid
);
112 if(itr
== m_playerSocialMap
.end()) // not exist
115 utf8truncate(note
,48); // DB and client size limitation
117 CharacterDatabase
.escape_string(note
);
118 CharacterDatabase
.PExecute("UPDATE character_social SET note = '%s' WHERE guid = '%u' AND friend = '%u'", note
.c_str(), GetPlayerGUID(), friend_guid
);
119 m_playerSocialMap
[friend_guid
].Note
= note
;
122 void PlayerSocial::SendSocialList()
124 Player
*plr
= objmgr
.GetPlayer(GetPlayerGUID());
128 uint32 size
= m_playerSocialMap
.size();
130 WorldPacket
data(SMSG_CONTACT_LIST
, (4+4+size
*25)); // just can guess size
131 data
<< uint32(7); // unk flag (0x1, 0x2, 0x4), 0x7 if it include ignore list
132 data
<< uint32(size
); // friends count
134 for(PlayerSocialMap::iterator itr
= m_playerSocialMap
.begin(); itr
!= m_playerSocialMap
.end(); ++itr
)
136 sSocialMgr
.GetFriendInfo(plr
, itr
->first
, itr
->second
);
138 data
<< uint64(itr
->first
); // player guid
139 data
<< uint32(itr
->second
.Flags
); // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?)
140 data
<< itr
->second
.Note
; // string note
141 if(itr
->second
.Flags
& SOCIAL_FLAG_FRIEND
) // if IsFriend()
143 data
<< uint8(itr
->second
.Status
); // online/offline/etc?
144 if(itr
->second
.Status
) // if online
146 data
<< uint32(itr
->second
.Area
); // player area
147 data
<< uint32(itr
->second
.Level
); // player level
148 data
<< uint32(itr
->second
.Class
); // player class
153 plr
->GetSession()->SendPacket(&data
);
154 sLog
.outDebug("WORLD: Sent SMSG_CONTACT_LIST");
157 bool PlayerSocial::HasFriend(uint32 friend_guid
)
159 PlayerSocialMap::iterator itr
= m_playerSocialMap
.find(friend_guid
);
160 if(itr
!= m_playerSocialMap
.end())
161 return itr
->second
.Flags
& SOCIAL_FLAG_FRIEND
;
165 bool PlayerSocial::HasIgnore(uint32 ignore_guid
)
167 PlayerSocialMap::iterator itr
= m_playerSocialMap
.find(ignore_guid
);
168 if(itr
!= m_playerSocialMap
.end())
169 return itr
->second
.Flags
& SOCIAL_FLAG_IGNORED
;
173 SocialMgr::SocialMgr()
178 SocialMgr::~SocialMgr()
183 void SocialMgr::RemovePlayerSocial(uint32 guid
)
185 SocialMap::iterator itr
= m_socialMap
.find(guid
);
186 if(itr
!= m_socialMap
.end())
187 m_socialMap
.erase(itr
);
190 void SocialMgr::GetFriendInfo(Player
*player
, uint32 friendGUID
, FriendInfo
&friendInfo
)
195 Player
*pFriend
= ObjectAccessor::FindPlayer(friendGUID
);
197 uint32 team
= player
->GetTeam();
198 uint32 security
= player
->GetSession()->GetSecurity();
199 bool allowTwoSideWhoList
= sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST
);
200 bool gmInWhoList
= sWorld
.getConfig(CONFIG_GM_IN_WHO_LIST
) || security
> SEC_PLAYER
;
202 PlayerSocialMap::iterator itr
= player
->GetSocial()->m_playerSocialMap
.find(friendGUID
);
203 if(itr
!= player
->GetSocial()->m_playerSocialMap
.end())
204 friendInfo
.Note
= itr
->second
.Note
;
206 // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
207 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
208 if( pFriend
&& pFriend
->GetName() &&
209 ( security
> SEC_PLAYER
||
210 ( pFriend
->GetTeam() == team
|| allowTwoSideWhoList
) &&
211 ( pFriend
->GetSession()->GetSecurity() == SEC_PLAYER
|| gmInWhoList
&& pFriend
->IsVisibleGloballyFor(player
) )))
213 friendInfo
.Status
= FRIEND_STATUS_ONLINE
;
215 friendInfo
.Status
= FRIEND_STATUS_AFK
;
217 friendInfo
.Status
= FRIEND_STATUS_DND
;
218 friendInfo
.Area
= pFriend
->GetZoneId();
219 friendInfo
.Level
= pFriend
->getLevel();
220 friendInfo
.Class
= pFriend
->getClass();
224 friendInfo
.Status
= FRIEND_STATUS_OFFLINE
;
226 friendInfo
.Level
= 0;
227 friendInfo
.Class
= 0;
231 void SocialMgr::MakeFriendStatusPacket(FriendsResult result
, uint32 guid
, WorldPacket
*data
)
233 data
->Initialize(SMSG_FRIEND_STATUS
, 5);
234 *data
<< uint8(result
);
235 *data
<< uint64(guid
);
238 void SocialMgr::SendFriendStatus(Player
*player
, FriendsResult result
, uint32 friend_guid
, bool broadcast
)
243 MakeFriendStatusPacket(result
, friend_guid
, &data
);
244 GetFriendInfo(player
, friend_guid
, fi
);
247 case FRIEND_ADDED_OFFLINE
:
248 case FRIEND_ADDED_ONLINE
:
255 case FRIEND_ADDED_ONLINE
:
257 data
<< uint8(fi
.Status
);
258 data
<< uint32(fi
.Area
);
259 data
<< uint32(fi
.Level
);
260 data
<< uint32(fi
.Class
);
265 BroadcastToFriendListers(player
, &data
);
267 player
->GetSession()->SendPacket(&data
);
270 void SocialMgr::BroadcastToFriendListers(Player
*player
, WorldPacket
*packet
)
275 uint32 team
= player
->GetTeam();
276 uint32 security
= player
->GetSession()->GetSecurity();
277 uint32 guid
= player
->GetGUIDLow();
278 bool gmInWhoList
= sWorld
.getConfig(CONFIG_GM_IN_WHO_LIST
);
279 bool allowTwoSideWhoList
= sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST
);
281 for(SocialMap::iterator itr
= m_socialMap
.begin(); itr
!= m_socialMap
.end(); ++itr
)
283 PlayerSocialMap::iterator itr2
= itr
->second
.m_playerSocialMap
.find(guid
);
284 if(itr2
!= itr
->second
.m_playerSocialMap
.end() && (itr2
->second
.Flags
& SOCIAL_FLAG_FRIEND
))
286 Player
*pFriend
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
288 // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
289 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
290 if( pFriend
&& pFriend
->IsInWorld() &&
291 ( pFriend
->GetSession()->GetSecurity() > SEC_PLAYER
||
292 ( pFriend
->GetTeam() == team
|| allowTwoSideWhoList
) &&
293 (security
== SEC_PLAYER
|| gmInWhoList
&& player
->IsVisibleGloballyFor(pFriend
) )))
295 pFriend
->GetSession()->SendPacket(packet
);
301 PlayerSocial
*SocialMgr::LoadFromDB(QueryResult
*result
, uint32 guid
)
303 PlayerSocial
*social
= &m_socialMap
[guid
];
304 social
->SetPlayerGUID(guid
);
309 uint32 friend_guid
= 0;
311 std::string note
= "";
313 // used to speed up check below. Using GetNumberOfSocialsWithFlag will cause unneeded iteration
314 uint32 friendCounter
=0, ignoreCounter
=0;
318 Field
*fields
= result
->Fetch();
320 friend_guid
= fields
[0].GetUInt32();
321 flags
= fields
[1].GetUInt32();
322 note
= fields
[2].GetCppString();
324 if((flags
& SOCIAL_FLAG_IGNORED
) && ignoreCounter
>= SOCIALMGR_IGNORE_LIMIT
)
326 if((flags
& SOCIAL_FLAG_FRIEND
) && friendCounter
>= SOCIALMGR_FRIEND_LIMIT
)
329 social
->m_playerSocialMap
[friend_guid
] = FriendInfo(flags
, note
);
331 if(flags
& SOCIAL_FLAG_IGNORED
)
336 while( result
->NextRow() );