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"
29 INSTANTIATE_SINGLETON_1( SocialMgr
);
31 PlayerSocial::PlayerSocial()
36 PlayerSocial::~PlayerSocial()
38 m_playerSocialMap
.clear();
41 uint32
PlayerSocial::GetNumberOfSocialsWithFlag(SocialFlag flag
)
44 for(PlayerSocialMap::const_iterator itr
= m_playerSocialMap
.begin(); itr
!= m_playerSocialMap
.end(); ++itr
)
46 if(itr
->second
.Flags
& flag
)
52 bool PlayerSocial::AddToSocialList(uint32 friend_guid
, bool ignore
)
54 // check client limits
57 if(GetNumberOfSocialsWithFlag(SOCIAL_FLAG_IGNORED
) >= SOCIALMGR_IGNORE_LIMIT
)
62 if(GetNumberOfSocialsWithFlag(SOCIAL_FLAG_FRIEND
) >= SOCIALMGR_FRIEND_LIMIT
)
66 uint32 flag
= SOCIAL_FLAG_FRIEND
;
68 flag
= SOCIAL_FLAG_IGNORED
;
70 PlayerSocialMap::const_iterator itr
= m_playerSocialMap
.find(friend_guid
);
71 if(itr
!= m_playerSocialMap
.end())
73 CharacterDatabase
.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag
, GetPlayerGUID(), friend_guid
);
74 m_playerSocialMap
[friend_guid
].Flags
|= flag
;
78 CharacterDatabase
.PExecute("INSERT INTO character_social (guid, friend, flags) VALUES ('%u', '%u', '%u')", GetPlayerGUID(), friend_guid
, flag
);
81 m_playerSocialMap
[friend_guid
] = fi
;
86 void PlayerSocial::RemoveFromSocialList(uint32 friend_guid
, bool ignore
)
88 PlayerSocialMap::iterator itr
= m_playerSocialMap
.find(friend_guid
);
89 if(itr
== m_playerSocialMap
.end()) // not exist
92 uint32 flag
= SOCIAL_FLAG_FRIEND
;
94 flag
= SOCIAL_FLAG_IGNORED
;
96 itr
->second
.Flags
&= ~flag
;
97 if(itr
->second
.Flags
== 0)
99 CharacterDatabase
.PExecute("DELETE FROM character_social WHERE guid = '%u' AND friend = '%u'", GetPlayerGUID(), friend_guid
);
100 m_playerSocialMap
.erase(itr
);
104 CharacterDatabase
.PExecute("UPDATE character_social SET flags = (flags & ~%u) WHERE guid = '%u' AND friend = '%u'", flag
, GetPlayerGUID(), friend_guid
);
108 void PlayerSocial::SetFriendNote(uint32 friend_guid
, std::string note
)
110 PlayerSocialMap::const_iterator itr
= m_playerSocialMap
.find(friend_guid
);
111 if(itr
== m_playerSocialMap
.end()) // not exist
114 utf8truncate(note
,48); // DB and client size limitation
116 CharacterDatabase
.escape_string(note
);
117 CharacterDatabase
.PExecute("UPDATE character_social SET note = '%s' WHERE guid = '%u' AND friend = '%u'", note
.c_str(), GetPlayerGUID(), friend_guid
);
118 m_playerSocialMap
[friend_guid
].Note
= note
;
121 void PlayerSocial::SendSocialList()
123 Player
*plr
= objmgr
.GetPlayer(GetPlayerGUID());
127 uint32 size
= m_playerSocialMap
.size();
129 WorldPacket
data(SMSG_CONTACT_LIST
, (4+4+size
*25)); // just can guess size
130 data
<< uint32(7); // unk flag (0x1, 0x2, 0x4), 0x7 if it include ignore list
131 data
<< uint32(size
); // friends count
133 for(PlayerSocialMap::iterator itr
= m_playerSocialMap
.begin(); itr
!= m_playerSocialMap
.end(); ++itr
)
135 sSocialMgr
.GetFriendInfo(plr
, itr
->first
, itr
->second
);
137 data
<< uint64(itr
->first
); // player guid
138 data
<< uint32(itr
->second
.Flags
); // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?)
139 data
<< itr
->second
.Note
; // string note
140 if(itr
->second
.Flags
& SOCIAL_FLAG_FRIEND
) // if IsFriend()
142 data
<< uint8(itr
->second
.Status
); // online/offline/etc?
143 if(itr
->second
.Status
) // if online
145 data
<< uint32(itr
->second
.Area
); // player area
146 data
<< uint32(itr
->second
.Level
); // player level
147 data
<< uint32(itr
->second
.Class
); // player class
152 plr
->GetSession()->SendPacket(&data
);
153 sLog
.outDebug("WORLD: Sent SMSG_CONTACT_LIST");
156 bool PlayerSocial::HasFriend(uint32 friend_guid
)
158 PlayerSocialMap::const_iterator itr
= m_playerSocialMap
.find(friend_guid
);
159 if(itr
!= m_playerSocialMap
.end())
160 return itr
->second
.Flags
& SOCIAL_FLAG_FRIEND
;
164 bool PlayerSocial::HasIgnore(uint32 ignore_guid
)
166 PlayerSocialMap::const_iterator itr
= m_playerSocialMap
.find(ignore_guid
);
167 if(itr
!= m_playerSocialMap
.end())
168 return itr
->second
.Flags
& SOCIAL_FLAG_IGNORED
;
172 SocialMgr::SocialMgr()
177 SocialMgr::~SocialMgr()
182 void SocialMgr::GetFriendInfo(Player
*player
, uint32 friendGUID
, FriendInfo
&friendInfo
)
187 Player
*pFriend
= ObjectAccessor::FindPlayer(friendGUID
);
189 uint32 team
= player
->GetTeam();
190 AccountTypes security
= player
->GetSession()->GetSecurity();
191 bool allowTwoSideWhoList
= sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST
);
192 AccountTypes gmLevelInWhoList
= AccountTypes (sWorld
.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST
));
194 PlayerSocialMap::iterator itr
= player
->GetSocial()->m_playerSocialMap
.find(friendGUID
);
195 if(itr
!= player
->GetSocial()->m_playerSocialMap
.end())
196 friendInfo
.Note
= itr
->second
.Note
;
198 // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
199 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
200 if (pFriend
&& pFriend
->GetName() &&
201 (security
> SEC_PLAYER
||
202 (pFriend
->GetTeam() == team
|| allowTwoSideWhoList
) && (pFriend
->GetSession()->GetSecurity() <= gmLevelInWhoList
)) &&
203 pFriend
->IsVisibleGloballyFor(player
))
205 friendInfo
.Status
= FRIEND_STATUS_ONLINE
;
207 friendInfo
.Status
= FRIEND_STATUS_AFK
;
209 friendInfo
.Status
= FRIEND_STATUS_DND
;
210 friendInfo
.Area
= pFriend
->GetZoneId();
211 friendInfo
.Level
= pFriend
->getLevel();
212 friendInfo
.Class
= pFriend
->getClass();
216 friendInfo
.Status
= FRIEND_STATUS_OFFLINE
;
218 friendInfo
.Level
= 0;
219 friendInfo
.Class
= 0;
223 void SocialMgr::MakeFriendStatusPacket(FriendsResult result
, uint32 guid
, WorldPacket
*data
)
225 data
->Initialize(SMSG_FRIEND_STATUS
, 5);
226 *data
<< uint8(result
);
227 *data
<< uint64(guid
);
230 void SocialMgr::SendFriendStatus(Player
*player
, FriendsResult result
, uint32 friend_guid
, bool broadcast
)
235 MakeFriendStatusPacket(result
, friend_guid
, &data
);
236 GetFriendInfo(player
, friend_guid
, fi
);
239 case FRIEND_ADDED_OFFLINE
:
240 case FRIEND_ADDED_ONLINE
:
249 case FRIEND_ADDED_ONLINE
:
251 data
<< uint8(fi
.Status
);
252 data
<< uint32(fi
.Area
);
253 data
<< uint32(fi
.Level
);
254 data
<< uint32(fi
.Class
);
261 BroadcastToFriendListers(player
, &data
);
263 player
->GetSession()->SendPacket(&data
);
266 void SocialMgr::BroadcastToFriendListers(Player
*player
, WorldPacket
*packet
)
271 uint32 team
= player
->GetTeam();
272 AccountTypes security
= player
->GetSession()->GetSecurity();
273 uint32 guid
= player
->GetGUIDLow();
274 AccountTypes gmLevelInWhoList
= AccountTypes(sWorld
.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST
));
275 bool allowTwoSideWhoList
= sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST
);
277 for(SocialMap::const_iterator itr
= m_socialMap
.begin(); itr
!= m_socialMap
.end(); ++itr
)
279 PlayerSocialMap::const_iterator itr2
= itr
->second
.m_playerSocialMap
.find(guid
);
280 if(itr2
!= itr
->second
.m_playerSocialMap
.end() && (itr2
->second
.Flags
& SOCIAL_FLAG_FRIEND
))
282 Player
*pFriend
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
284 // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
285 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
286 if (pFriend
&& pFriend
->IsInWorld() &&
287 (pFriend
->GetSession()->GetSecurity() > SEC_PLAYER
||
288 (pFriend
->GetTeam() == team
|| allowTwoSideWhoList
) && security
<= gmLevelInWhoList
) &&
289 player
->IsVisibleGloballyFor(pFriend
))
291 pFriend
->GetSession()->SendPacket(packet
);
297 PlayerSocial
*SocialMgr::LoadFromDB(QueryResult
*result
, uint32 guid
)
299 PlayerSocial
*social
= &m_socialMap
[guid
];
300 social
->SetPlayerGUID(guid
);
305 uint32 friend_guid
= 0;
307 std::string note
= "";
309 // used to speed up check below. Using GetNumberOfSocialsWithFlag will cause unneeded iteration
310 uint32 friendCounter
=0, ignoreCounter
=0;
314 Field
*fields
= result
->Fetch();
316 friend_guid
= fields
[0].GetUInt32();
317 flags
= fields
[1].GetUInt32();
318 note
= fields
[2].GetCppString();
320 if((flags
& SOCIAL_FLAG_IGNORED
) && ignoreCounter
>= SOCIALMGR_IGNORE_LIMIT
)
322 if((flags
& SOCIAL_FLAG_FRIEND
) && friendCounter
>= SOCIALMGR_FRIEND_LIMIT
)
325 social
->m_playerSocialMap
[friend_guid
] = FriendInfo(flags
, note
);
327 if(flags
& SOCIAL_FLAG_IGNORED
)
332 while( result
->NextRow() );