2 * Copyright (C) 2005-2009 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"
25 #include "ObjectMgr.h"
26 #include "ObjectDefines.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::const_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::const_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::const_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
= sObjectMgr
.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::const_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::const_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::GetFriendInfo(Player
*player
, uint32 friendGUID
, FriendInfo
&friendInfo
)
188 Player
*pFriend
= ObjectAccessor::FindPlayer(friendGUID
);
190 uint32 team
= player
->GetTeam();
191 AccountTypes security
= player
->GetSession()->GetSecurity();
192 bool allowTwoSideWhoList
= sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST
);
193 AccountTypes gmLevelInWhoList
= AccountTypes (sWorld
.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST
));
195 PlayerSocialMap::iterator itr
= player
->GetSocial()->m_playerSocialMap
.find(friendGUID
);
196 if(itr
!= player
->GetSocial()->m_playerSocialMap
.end())
197 friendInfo
.Note
= itr
->second
.Note
;
199 // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
200 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
201 if (pFriend
&& pFriend
->GetName() &&
202 (security
> SEC_PLAYER
||
203 ((pFriend
->GetTeam() == team
|| allowTwoSideWhoList
) && (pFriend
->GetSession()->GetSecurity() <= gmLevelInWhoList
))) &&
204 pFriend
->IsVisibleGloballyFor(player
))
206 friendInfo
.Status
= FRIEND_STATUS_ONLINE
;
208 friendInfo
.Status
= FRIEND_STATUS_AFK
;
210 friendInfo
.Status
= FRIEND_STATUS_DND
;
211 friendInfo
.Area
= pFriend
->GetZoneId();
212 friendInfo
.Level
= pFriend
->getLevel();
213 friendInfo
.Class
= pFriend
->getClass();
217 friendInfo
.Status
= FRIEND_STATUS_OFFLINE
;
219 friendInfo
.Level
= 0;
220 friendInfo
.Class
= 0;
224 void SocialMgr::MakeFriendStatusPacket(FriendsResult result
, uint32 guid
, WorldPacket
*data
)
226 data
->Initialize(SMSG_FRIEND_STATUS
, 5);
227 *data
<< uint8(result
);
228 *data
<< uint64(guid
);
231 void SocialMgr::SendFriendStatus(Player
*player
, FriendsResult result
, uint32 friend_guid
, bool broadcast
)
236 MakeFriendStatusPacket(result
, friend_guid
, &data
);
237 GetFriendInfo(player
, friend_guid
, fi
);
240 case FRIEND_ADDED_OFFLINE
:
241 case FRIEND_ADDED_ONLINE
:
250 case FRIEND_ADDED_ONLINE
:
252 data
<< uint8(fi
.Status
);
253 data
<< uint32(fi
.Area
);
254 data
<< uint32(fi
.Level
);
255 data
<< uint32(fi
.Class
);
262 BroadcastToFriendListers(player
, &data
);
264 player
->GetSession()->SendPacket(&data
);
267 void SocialMgr::BroadcastToFriendListers(Player
*player
, WorldPacket
*packet
)
272 uint32 team
= player
->GetTeam();
273 AccountTypes security
= player
->GetSession()->GetSecurity();
274 uint32 guid
= player
->GetGUIDLow();
275 AccountTypes gmLevelInWhoList
= AccountTypes(sWorld
.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST
));
276 bool allowTwoSideWhoList
= sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST
);
278 for(SocialMap::const_iterator itr
= m_socialMap
.begin(); itr
!= m_socialMap
.end(); ++itr
)
280 PlayerSocialMap::const_iterator itr2
= itr
->second
.m_playerSocialMap
.find(guid
);
281 if(itr2
!= itr
->second
.m_playerSocialMap
.end() && (itr2
->second
.Flags
& SOCIAL_FLAG_FRIEND
))
283 Player
*pFriend
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
285 // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
286 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
287 if (pFriend
&& pFriend
->IsInWorld() &&
288 (pFriend
->GetSession()->GetSecurity() > SEC_PLAYER
||
289 ((pFriend
->GetTeam() == team
|| allowTwoSideWhoList
) && security
<= gmLevelInWhoList
)) &&
290 player
->IsVisibleGloballyFor(pFriend
))
292 pFriend
->GetSession()->SendPacket(packet
);
298 PlayerSocial
*SocialMgr::LoadFromDB(QueryResult
*result
, uint32 guid
)
300 PlayerSocial
*social
= &m_socialMap
[guid
];
301 social
->SetPlayerGUID(guid
);
306 uint32 friend_guid
= 0;
308 std::string note
= "";
310 // used to speed up check below. Using GetNumberOfSocialsWithFlag will cause unneeded iteration
311 uint32 friendCounter
=0, ignoreCounter
=0;
315 Field
*fields
= result
->Fetch();
317 friend_guid
= fields
[0].GetUInt32();
318 flags
= fields
[1].GetUInt32();
319 note
= fields
[2].GetCppString();
321 if((flags
& SOCIAL_FLAG_IGNORED
) && ignoreCounter
>= SOCIALMGR_IGNORE_LIMIT
)
323 if((flags
& SOCIAL_FLAG_FRIEND
) && friendCounter
>= SOCIALMGR_FRIEND_LIMIT
)
326 social
->m_playerSocialMap
[friend_guid
] = FriendInfo(flags
, note
);
328 if(flags
& SOCIAL_FLAG_IGNORED
)
333 while( result
->NextRow() );