TrinityCore
Loading...
Searching...
No Matches
GroupMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "GroupMgr.h"
19#include "Common.h"
20#include "DatabaseEnv.h"
21#include "DBCStores.h"
22#include "InstanceSaveMgr.h"
23#include "Log.h"
24#include "World.h"
25
31
33{
34 for (GroupContainer::iterator itr = GroupStore.begin(); itr != GroupStore.end(); ++itr)
35 delete itr->second;
36}
37
39{
40 uint32 newStorageId = NextGroupDbStoreId;
41
42 for (uint32 i = ++NextGroupDbStoreId; i < 0xFFFFFFFF; ++i)
43 {
44 if ((i < GroupDbStore.size() && GroupDbStore[i] == nullptr) || i >= GroupDbStore.size())
45 {
47 break;
48 }
49 }
50
51 if (newStorageId == NextGroupDbStoreId)
52 {
53 TC_LOG_ERROR("misc", "Group storage ID overflow!! Can't continue, shutting down server. ");
55 }
56
57 return newStorageId;
58}
59
61{
62 // Allocate space if necessary.
63 if (storageId >= uint32(GroupDbStore.size()))
64 GroupDbStore.resize(storageId + 1);
65
66 GroupDbStore[storageId] = group;
67}
68
70{
71 uint32 storageId = group->GetDbStoreId();
72
73 if (storageId < NextGroupDbStoreId)
74 NextGroupDbStoreId = storageId;
75
76 GroupDbStore[storageId] = nullptr;
77}
78
80{
81 if (storageId < GroupDbStore.size())
82 return GroupDbStore[storageId];
83
84 return nullptr;
85}
86
88{
89 if (NextGroupId >= 0xFFFFFFFE)
90 {
91 TC_LOG_ERROR("misc", "Group guid overflow!! Can't continue, shutting down server. ");
93 }
94 return NextGroupId++;
95}
96
98{
99 static GroupMgr instance;
100 return &instance;
101}
102
104{
105 GroupContainer::const_iterator itr = GroupStore.find(groupId.GetCounter());
106 if (itr != GroupStore.end())
107 return itr->second;
108
109 return nullptr;
110}
111
113{
114 for (auto group : GroupStore)
115 group.second->Update(diff);
116}
117
119{
120 GroupStore[group->GetGUID().GetCounter()] = group;
121}
122
124{
125 GroupStore.erase(group->GetGUID().GetCounter());
126}
127
129{
130 {
131 uint32 oldMSTime = getMSTime();
132
133 // Delete all groups whose leader does not exist
134 CharacterDatabase.DirectExecute("DELETE FROM `groups` WHERE leaderGuid NOT IN (SELECT guid FROM characters)");
135 // Delete all groups with less than 2 members
136 CharacterDatabase.DirectExecute("DELETE FROM `groups` WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)");
137
138 // 0 1 2 3 4 5 6 7 8 9
139 QueryResult result = CharacterDatabase.Query("SELECT g.leaderGuid, g.lootMethod, g.looterGuid, g.lootThreshold, g.icon1, g.icon2, g.icon3, g.icon4, g.icon5, g.icon6"
140 // 10 11 12 13 14 15 16 17 18
141 ", g.icon7, g.icon8, g.groupType, g.difficulty, g.raidDifficulty, g.masterLooterGuid, g.guid, lfg.dungeon, lfg.state FROM `groups` g LEFT JOIN lfg_data lfg ON lfg.guid = g.guid ORDER BY g.guid ASC");
142 if (!result)
143 {
144 TC_LOG_INFO("server.loading", ">> Loaded 0 group definitions. DB table `groups` is empty!");
145 return;
146 }
147
148 uint32 count = 0;
149 do
150 {
151 Field* fields = result->Fetch();
152 Group* group = new Group;
153 group->LoadGroupFromDB(fields);
154 AddGroup(group);
155
156 // Get the ID used for storing the group in the database and register it in the pool.
157 uint32 storageId = group->GetDbStoreId();
158
159 RegisterGroupDbStoreId(storageId, group);
160
161 // Increase the next available storage ID
162 if (storageId == NextGroupDbStoreId)
164
165 ++count;
166 }
167 while (result->NextRow());
168
169 TC_LOG_INFO("server.loading", ">> Loaded {} group definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
170 }
171
172 TC_LOG_INFO("server.loading", "Loading Group members...");
173 {
174 uint32 oldMSTime = getMSTime();
175
176 // Delete all rows from group_member or group_instance with no group
177 CharacterDatabase.DirectExecute("DELETE FROM group_member WHERE guid NOT IN (SELECT guid FROM `groups`)");
178 CharacterDatabase.DirectExecute("DELETE FROM group_instance WHERE guid NOT IN (SELECT guid FROM `groups`)");
179 // Delete all members that does not exist
180 CharacterDatabase.DirectExecute("DELETE FROM group_member WHERE memberGuid NOT IN (SELECT guid FROM characters)");
181
182 // 0 1 2 3 4
183 QueryResult result = CharacterDatabase.Query("SELECT guid, memberGuid, memberFlags, subgroup, roles FROM group_member ORDER BY guid");
184 if (!result)
185 {
186 TC_LOG_INFO("server.loading", ">> Loaded 0 group members. DB table `group_member` is empty!");
187 return;
188 }
189
190 uint32 count = 0;
191
192 do
193 {
194 Field* fields = result->Fetch();
195 Group* group = GetGroupByDbStoreId(fields[0].GetUInt32());
196
197 if (group)
198 group->LoadMemberFromDB(fields[1].GetUInt32(), fields[2].GetUInt8(), fields[3].GetUInt8(), fields[4].GetUInt8());
199 else
200 TC_LOG_ERROR("misc", "GroupMgr::LoadGroups: Consistency failed, can't find group (storage id: {})", fields[0].GetUInt32());
201
202 ++count;
203 }
204 while (result->NextRow());
205
206 TC_LOG_INFO("server.loading", ">> Loaded {} group members in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
207 }
208
209 TC_LOG_INFO("server.loading", "Loading Group instance saves...");
210 {
211 uint32 oldMSTime = getMSTime();
212
213 // 0 1 2 3 4 5
214 QueryResult result = CharacterDatabase.Query("SELECT gi.guid, i.map, gi.instance, gi.permanent, i.difficulty, i.resettime, "
215 // 6
216 "(SELECT COUNT(1) FROM character_instance ci LEFT JOIN `groups` g ON ci.guid = g.leaderGuid WHERE ci.instance = gi.instance AND ci.permanent = 1 LIMIT 1) "
217 "FROM group_instance gi LEFT JOIN instance i ON gi.instance = i.id ORDER BY guid");
218
219 if (!result)
220 {
221 TC_LOG_INFO("server.loading", ">> Loaded 0 group-instance saves. DB table `group_instance` is empty!");
222 return;
223 }
224
225 uint32 count = 0;
226 do
227 {
228 Field* fields = result->Fetch();
229 Group* group = GetGroupByDbStoreId(fields[0].GetUInt32());
230 // group will never be NULL (we have run consistency sql's before loading)
231 ASSERT(group);
232
233 MapEntry const* mapEntry = sMapStore.LookupEntry(fields[1].GetUInt16());
234 if (!mapEntry || !mapEntry->IsDungeon())
235 {
236 TC_LOG_ERROR("sql.sql", "Incorrect entry in group_instance table : no dungeon map {}", fields[1].GetUInt16());
237 continue;
238 }
239
240 uint32 diff = fields[4].GetUInt8();
241 if (diff >= uint32(mapEntry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY))
242 {
243 TC_LOG_ERROR("sql.sql", "Wrong dungeon difficulty use in group_instance table: {}", diff + 1);
244 diff = 0; // default for both difficaly types
245 }
246
247 InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapEntry->ID, fields[2].GetUInt32(), Difficulty(diff), time_t(fields[5].GetUInt64()), fields[6].GetUInt64() == 0, true);
248 group->BindToInstance(save, fields[3].GetBool(), true);
249 ++count;
250 }
251 while (result->NextRow());
252
253 TC_LOG_INFO("server.loading", ">> Loaded {} group-instance saves in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
254 }
255}
#define MAX_RAID_DIFFICULTY
Definition DBCEnums.h:295
Difficulty
Definition DBCEnums.h:279
#define MAX_DUNGEON_DIFFICULTY
Definition DBCEnums.h:294
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
#define sInstanceSaveMgr
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
uint32 GetUInt32() const
Definition Field.cpp:61
static GroupMgr * instance()
Definition GroupMgr.cpp:97
void FreeGroupDbStoreId(Group *group)
Definition GroupMgr.cpp:69
Group * GetGroupByDbStoreId(uint32 storageId) const
Definition GroupMgr.cpp:79
uint32 GenerateNewGroupDbStoreId()
Definition GroupMgr.cpp:38
Group * GetGroupByGUID(ObjectGuid const &guid) const
Definition GroupMgr.cpp:103
void RemoveGroup(Group *group)
Definition GroupMgr.cpp:123
ObjectGuid::LowType NextGroupId
Definition GroupMgr.h:52
void Update(uint32 diff)
Definition GroupMgr.cpp:112
GroupDbContainer GroupDbStore
Definition GroupMgr.h:55
uint32 NextGroupDbStoreId
Definition GroupMgr.h:53
void LoadGroups()
Definition GroupMgr.cpp:128
void AddGroup(Group *group)
Definition GroupMgr.cpp:118
ObjectGuid::LowType GenerateGroupId()
Definition GroupMgr.cpp:87
void RegisterGroupDbStoreId(uint32 storageId, Group *group)
Definition GroupMgr.cpp:60
GroupContainer GroupStore
Definition GroupMgr.h:54
Definition Group.h:165
InstanceGroupBind * BindToInstance(InstanceSave *save, bool permanent, bool load=false)
Definition Group.cpp:2321
void LoadGroupFromDB(Field *field)
Definition Group.cpp:221
ObjectGuid GetGUID() const
Definition Group.cpp:2473
void Update(uint32 diff)
Definition Group.cpp:102
void LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uint8 subgroup, uint8 roles)
Definition Group.cpp:260
uint32 GetDbStoreId() const
Definition Group.h:226
LowType GetCounter() const
Definition ObjectGuid.h:156
uint32 LowType
Definition ObjectGuid.h:142
static void StopNow(uint8 exitcode)
Definition World.h:673
@ ERROR_EXIT_CODE
Definition World.h:64
bool IsDungeon() const
bool IsRaid() const