TrinityCore
Loading...
Searching...
No Matches
AreaTriggerDataStore.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
19#include "AreaTriggerTemplate.h"
20#include "DB2Stores.h"
21#include "DatabaseEnv.h"
22#include "Log.h"
23#include "MapManager.h"
24#include "MapUtils.h"
25#include "ObjectMgr.h"
27#include "SpellMgr.h"
28#include "Timer.h"
29#include "Types.h"
30#include <cmath>
31
32template <>
33struct std::hash<AreaTriggerId>
34{
35 std::size_t operator()(AreaTriggerId const& value) const noexcept
36 {
38 hash.UpdateData(value.Id);
39 hash.UpdateData(value.IsCustom);
40 return hash.Value;
41 }
42};
43
44namespace
45{
46 typedef std::unordered_map<uint32/*grid_id*/, Trinity::Containers::FlatSet<ObjectGuid::LowType>> AtCellObjectGuidsMap;
47 typedef std::unordered_map<std::pair<uint32 /*mapId*/, Difficulty>, AtCellObjectGuidsMap> AtMapObjectGuids;
48
49 AtMapObjectGuids _areaTriggerSpawnsByLocation;
50 std::unordered_map<ObjectGuid::LowType, AreaTriggerSpawn> _areaTriggerSpawnsBySpawnId;
51 std::unordered_map<AreaTriggerId, AreaTriggerTemplate> _areaTriggerTemplateStore;
52 std::unordered_map<AreaTriggerCreatePropertiesId, AreaTriggerCreateProperties> _areaTriggerCreateProperties;
53}
54
56{
57 uint32 oldMSTime = getMSTime();
58 std::unordered_map<AreaTriggerCreatePropertiesId, std::vector<TaggedPosition<Position::XY>>> verticesByCreateProperties;
59 std::unordered_map<AreaTriggerCreatePropertiesId, std::vector<TaggedPosition<Position::XY>>> verticesTargetByCreateProperties;
60 std::unordered_map<AreaTriggerCreatePropertiesId, std::vector<Position>> splinesByCreateProperties;
61 std::unordered_map<AreaTriggerId, std::vector<AreaTriggerAction>> actionsByAreaTrigger;
62
63 // 0 1 2 3 4
64 if (QueryResult templateActions = WorldDatabase.Query("SELECT AreaTriggerId, IsCustom, ActionType, ActionParam, TargetType FROM `areatrigger_template_actions`"))
65 {
66 do
67 {
68 Field* templateActionFields = templateActions->Fetch();
69 AreaTriggerId areaTriggerId = { templateActionFields[0].GetUInt32(), templateActionFields[1].GetBool()};
70
71 AreaTriggerAction action;
72 action.Param = templateActionFields[3].GetUInt32();
73 uint32 actionType = templateActionFields[2].GetUInt32();
74 uint32 targetType = templateActionFields[4].GetUInt32();
75
76 if (actionType >= AREATRIGGER_ACTION_MAX)
77 {
78 TC_LOG_ERROR("sql.sql", "Table `areatrigger_template_actions` has invalid ActionType {} for AreaTriggerId ({},{}) and Param {}",
79 actionType, areaTriggerId.Id, uint32(areaTriggerId.IsCustom), action.Param);
80 continue;
81 }
82
83 if (targetType >= AREATRIGGER_ACTION_USER_MAX)
84 {
85 TC_LOG_ERROR("sql.sql", "Table `areatrigger_template_actions` has invalid TargetType {} for AreaTriggerId ({},{}) and Param {}",
86 targetType, areaTriggerId.Id, uint32(areaTriggerId.IsCustom), action.Param);
87 continue;
88 }
89
90 if (actionType == AREATRIGGER_ACTION_TELEPORT)
91 {
92 if (!sObjectMgr->GetWorldSafeLoc(action.Param))
93 {
94 TC_LOG_ERROR("sql.sql", "Table `areatrigger_template_actions` has invalid entry for AreaTriggerId ({},{}) with TargetType=Teleport and Param ({}) not a valid world safe loc entry",
95 areaTriggerId.Id, uint32(areaTriggerId.IsCustom), action.Param);
96 continue;
97 }
98 }
99
100 action.TargetType = AreaTriggerActionUserTypes(targetType);
101 action.ActionType = AreaTriggerActionTypes(actionType);
102
103 actionsByAreaTrigger[areaTriggerId].push_back(action);
104 }
105 while (templateActions->NextRow());
106 }
107 else
108 {
109 TC_LOG_INFO("server.loading", ">> Loaded 0 AreaTrigger templates actions. DB table `areatrigger_template_actions` is empty.");
110 }
111
112 // 0 1 2 3 4 5 6
113 if (QueryResult vertices = WorldDatabase.Query("SELECT AreaTriggerCreatePropertiesId, IsCustom, Idx, VerticeX, VerticeY, VerticeTargetX, VerticeTargetY FROM `areatrigger_create_properties_polygon_vertex` ORDER BY `AreaTriggerCreatePropertiesId`, `IsCustom`, `Idx`"))
114 {
115 do
116 {
117 Field* verticeFields = vertices->Fetch();
118 AreaTriggerCreatePropertiesId createPropertiesId = { verticeFields[0].GetUInt32(), verticeFields[1].GetBool() };
119
120 verticesByCreateProperties[createPropertiesId].emplace_back(verticeFields[3].GetFloat(), verticeFields[4].GetFloat());
121
122 if (!verticeFields[5].IsNull() && !verticeFields[6].IsNull())
123 verticesTargetByCreateProperties[createPropertiesId].emplace_back(verticeFields[5].GetFloat(), verticeFields[6].GetFloat());
124 else if (verticeFields[5].IsNull() != verticeFields[6].IsNull())
125 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties_polygon_vertex` has listed invalid target vertices (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {}), Index: {}).",
126 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), verticeFields[1].GetUInt32());
127 }
128 while (vertices->NextRow());
129 }
130 else
131 {
132 TC_LOG_INFO("server.loading", ">> Loaded 0 AreaTrigger polygon vertices. DB table `areatrigger_create_properties_polygon_vertex` is empty.");
133 }
134
135 // 0 1 2 3, 4
136 if (QueryResult splines = WorldDatabase.Query("SELECT AreaTriggerCreatePropertiesId, IsCustom, X, Y, Z FROM `areatrigger_create_properties_spline_point` ORDER BY `AreaTriggerCreatePropertiesId`, `IsCustom`, `Idx`"))
137 {
138 do
139 {
140 Field* splineFields = splines->Fetch();
141 AreaTriggerCreatePropertiesId createPropertiesId = { splineFields[0].GetUInt32(), splineFields[1].GetBool() };
142 splinesByCreateProperties[createPropertiesId].emplace_back(splineFields[2].GetFloat(), splineFields[3].GetFloat(), splineFields[4].GetFloat());
143 }
144 while (splines->NextRow());
145 }
146 else
147 {
148 TC_LOG_INFO("server.loading", ">> Loaded 0 AreaTrigger splines. DB table `areatrigger_create_properties_spline_point` is empty.");
149 }
150
151 // 0 1 2 3 4
152 if (QueryResult templates = WorldDatabase.Query("SELECT Id, IsCustom, Flags, ActionSetId, ActionSetFlags FROM `areatrigger_template`"))
153 {
154 do
155 {
156 Field* fields = templates->Fetch();
157
158 AreaTriggerTemplate areaTriggerTemplate;
159 areaTriggerTemplate.Id.Id = fields[0].GetUInt32();
160 areaTriggerTemplate.Id.IsCustom = fields[1].GetBool();
161 areaTriggerTemplate.Flags = AreaTriggerFlag(fields[2].GetUInt32());
162 areaTriggerTemplate.ActionSetId = fields[3].GetUInt32();
163 areaTriggerTemplate.ActionSetFlags = AreaTriggerActionSetFlag(fields[4].GetUInt32());
164 areaTriggerTemplate.Actions = std::move(actionsByAreaTrigger[areaTriggerTemplate.Id]);
165
166 _areaTriggerTemplateStore[areaTriggerTemplate.Id] = areaTriggerTemplate;
167 }
168 while (templates->NextRow());
169 }
170
171 if (QueryResult areatriggerCreateProperties = WorldDatabase.Query("SELECT Id, IsCustom, AreaTriggerId, IsAreatriggerCustom, Flags, "
172 "MoveCurveId, ScaleCurveId, MorphCurveId, FacingCurveId, AnimId, AnimKitId, DecalPropertiesId, SpellForVisuals, "
173 "PositionalSoundKitId, TimeToTargetScale, Speed, SpeedIsTime, "
174 "Shape, ShapeData0, ShapeData1, ShapeData2, ShapeData3, ShapeData4, ShapeData5, ShapeData6, ShapeData7, "
175 "Roll, Pitch, Yaw, TargetRoll, TargetPitch, TargetYaw, ScriptName FROM `areatrigger_create_properties`"))
176 {
177 do
178 {
179 DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(ResultSet, (Id)(IsCustom)(AreaTriggerId)(IsAreatriggerCustom)(Flags)
180 (MoveCurveId)(ScaleCurveId)(MorphCurveId)(FacingCurveId)(AnimId)(AnimKitId)(DecalPropertiesId)(SpellForVisuals)
181 (PositionalSoundKitId)(TimeToTargetScale)(Speed)(SpeedIsTime)
182 (Shape)(ShapeData0)(ShapeData1)(ShapeData2)(ShapeData3)(ShapeData4)(ShapeData5)(ShapeData6)(ShapeData7)
183 (Roll)(Pitch)(Yaw)(TargetRoll)(TargetPitch)(TargetYaw)(ScriptName)
184 ) fields { *areatriggerCreateProperties };
185
186 AreaTriggerCreatePropertiesId createPropertiesId = { fields.Id().GetUInt32(), fields.IsCustom().GetBool() };
187
188 AreaTriggerId areaTriggerId = { fields.AreaTriggerId().GetUInt32(), fields.IsAreatriggerCustom().GetBool() };
189 AreaTriggerTemplate const* areaTriggerTemplate = GetAreaTriggerTemplate(areaTriggerId);
190
191 AreaTriggerShapeType shape = AreaTriggerShapeType(fields.Shape().GetUInt8());
192
193 if (areaTriggerId.Id && !areaTriggerTemplate)
194 {
195 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties` references invalid AreaTrigger (Id: {}, IsCustom: {}) for AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {})",
196 areaTriggerId.Id, uint32(areaTriggerId.IsCustom), createPropertiesId.Id, uint32(createPropertiesId.IsCustom));
197 continue;
198 }
199
201 {
202 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties` has listed AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with invalid shape {}.",
203 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), uint32(shape));
204 continue;
205 }
206
207 AreaTriggerCreateProperties& createProperties = _areaTriggerCreateProperties[createPropertiesId];
208 createProperties.Id = createPropertiesId;
209 createProperties.Template = areaTriggerTemplate;
210 createProperties.Flags = AreaTriggerCreatePropertiesFlag(fields.Flags().GetUInt32());
211
212#define VALIDATE_AND_SET_CURVE(Curve, Value) \
213 createProperties.Curve = Value; \
214 if (createProperties.Curve && !sCurveStore.HasRecord(createProperties.Curve)) \
215 { \
216 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties` has listed AreaTrigger (Id: {}, IsCustom: {}) for AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with invalid " #Curve " ({}), set to 0!", \
217 areaTriggerId.Id, uint32(areaTriggerId.IsCustom), createPropertiesId.Id, uint32(createPropertiesId.IsCustom), createProperties.Curve); \
218 createProperties.Curve = 0; \
219 }
220
221 VALIDATE_AND_SET_CURVE(MoveCurveId, fields.MoveCurveId().GetUInt32());
222 VALIDATE_AND_SET_CURVE(ScaleCurveId, fields.ScaleCurveId().GetUInt32());
223 VALIDATE_AND_SET_CURVE(MorphCurveId, fields.MorphCurveId().GetUInt32());
224 VALIDATE_AND_SET_CURVE(FacingCurveId, fields.FacingCurveId().GetUInt32());
225
226#undef VALIDATE_AND_SET_CURVE
227
228 createProperties.AnimId = fields.AnimId().GetInt32();
229 createProperties.AnimKitId = fields.AnimKitId().GetInt32();
230
231 createProperties.DecalPropertiesId = fields.DecalPropertiesId().GetUInt32();
232 createProperties.SpellForVisuals = fields.SpellForVisuals().GetInt32OrNull();
233
234 if (createProperties.SpellForVisuals)
235 {
236 if (!sSpellMgr->GetSpellInfo(*createProperties.SpellForVisuals, DIFFICULTY_NONE))
237 {
238 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties` has AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with invalid SpellForVisual {}, set to none.", createPropertiesId.Id, uint32(createPropertiesId.IsCustom), *createProperties.SpellForVisuals);
239 createProperties.SpellForVisuals.reset();
240 }
241 }
242
243 createProperties.PositionalSoundKitId = fields.PositionalSoundKitId().GetInt32();
244 if (createProperties.PositionalSoundKitId)
245 {
246 if (!sSoundKitStore.HasRecord(createProperties.PositionalSoundKitId))
247 {
248 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties` has AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with invalid PositionalSoundKitId {}, set to 0.",
249 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), createProperties.PositionalSoundKitId);
250 createProperties.PositionalSoundKitId = 0;
251 }
253 {
254 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties` has AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with PositionalSoundKitId {} on unsupported shape {}, set to 0.",
255 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), createProperties.PositionalSoundKitId, uint32(shape));
256 createProperties.PositionalSoundKitId = 0;
257 }
258 }
259
260 createProperties.TimeToTargetScale = fields.TimeToTargetScale().GetUInt32();
261 createProperties.Speed = fields.Speed().GetFloat();
262 createProperties.SpeedIsTime = fields.SpeedIsTime().GetBool();
263
264 std::array<float, MAX_AREATRIGGER_ENTITY_DATA> shapeData =
265 {
266 fields.ShapeData0().GetFloat(), fields.ShapeData1().GetFloat(), fields.ShapeData2().GetFloat(), fields.ShapeData3().GetFloat(),
267 fields.ShapeData4().GetFloat(), fields.ShapeData5().GetFloat(), fields.ShapeData6().GetFloat(), fields.ShapeData7().GetFloat()
268 };
269
270 switch (shape)
271 {
273 createProperties.Shape.Data.emplace<AreaTriggerShapeInfo::Sphere>(shapeData);
274 break;
276 createProperties.Shape.Data.emplace<AreaTriggerShapeInfo::Box>(shapeData);
277 break;
280 {
281 AreaTriggerShapeInfo::Polygon& polygon = createProperties.Shape.Data.emplace<AreaTriggerShapeInfo::Polygon>(shape, shapeData);
282 if (polygon.Height <= 0.0f)
283 {
284 polygon.Height = 1.0f;
285 if (polygon.HeightTarget <= 0.0f)
286 polygon.HeightTarget = 1.0f;
287 }
288 if (std::vector<TaggedPosition<Position::XY>>* vertices = Trinity::Containers::MapGetValuePtr(verticesByCreateProperties, createProperties.Id))
289 polygon.PolygonVertices = std::move(*vertices);
290 if (std::vector<TaggedPosition<Position::XY>>* vertices = Trinity::Containers::MapGetValuePtr(verticesTargetByCreateProperties, createProperties.Id))
291 polygon.PolygonVerticesTarget = std::move(*vertices);
292 if (!polygon.PolygonVerticesTarget.empty() && polygon.PolygonVertices.size() != polygon.PolygonVerticesTarget.size())
293 {
294 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties_polygon_vertex` has invalid target vertices, either all or none vertices must have a corresponding target vertex (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})).",
295 createPropertiesId.Id, uint32(createPropertiesId.IsCustom));
296 polygon.PolygonVerticesTarget.clear();
297 }
298 break;
299 }
301 createProperties.Shape.Data.emplace<AreaTriggerShapeInfo::Cylinder>(shapeData);
302 break;
304 createProperties.Shape.Data.emplace<AreaTriggerShapeInfo::Disk>(shapeData);
305 break;
307 createProperties.Shape.Data.emplace<AreaTriggerShapeInfo::BoundedPlane>(shapeData);
308 break;
309 default:
310 break;
311 }
312
313 createProperties.RollPitchYaw.Pos.Relocate(
314 fields.Roll().GetFloat(),
315 fields.Pitch().GetFloat(),
316 fields.Yaw().GetFloat());
317
318 std::array<Optional<float>, 3> targetRollPitchYaw =
319 {
320 fields.TargetRoll().GetFloatOrNull(),
321 fields.TargetPitch().GetFloatOrNull(),
322 fields.TargetYaw().GetFloatOrNull()
323 };
324
325 if (std::ptrdiff_t trpyFields = std::ranges::count_if(targetRollPitchYaw, [](Optional<float> const& angle) { return angle.has_value(); }); trpyFields == 3)
326 {
327 createProperties.TargetRollPitchYaw.emplace(
328 *targetRollPitchYaw[0],
329 *targetRollPitchYaw[1],
330 *targetRollPitchYaw[2]);
331 }
332 else if (trpyFields)
333 {
334 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties` has AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with invalid TargetRoll {}, TargetPitch {}, TargetYaw {} combination, they must either all be NULL or all have value, ignored.",
335 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), targetRollPitchYaw[0], targetRollPitchYaw[1], targetRollPitchYaw[2]);
336 }
337
338 createProperties.ScriptId = sObjectMgr->GetScriptId(fields.ScriptName().GetStringView());
339
340 if (std::vector<Position>* spline = Trinity::Containers::MapGetValuePtr(splinesByCreateProperties, createProperties.Id))
341 createProperties.Movement = std::move(*spline);
342 }
343 while (areatriggerCreateProperties->NextRow());
344 }
345 else
346 {
347 TC_LOG_INFO("server.loading", ">> Loaded 0 AreaTrigger create properties. DB table `areatrigger_create_properties` is empty.");
348 }
349
350 // 0 1 2 3 4 5 6 7 8
351 if (QueryResult circularMovementInfos = WorldDatabase.Query("SELECT AreaTriggerCreatePropertiesId, IsCustom, ExtraTimeForBlending, CircleRadius, BlendFromRadius, InitialAngle, ZOffset, CounterClockwise, CanLoop FROM `areatrigger_create_properties_orbit`"))
352 {
353 do
354 {
355 Field* circularMovementInfoFields = circularMovementInfos->Fetch();
356 AreaTriggerCreatePropertiesId createPropertiesId = { circularMovementInfoFields[0].GetUInt32(), circularMovementInfoFields[1].GetBool() };
357
358 AreaTriggerCreateProperties* createProperties = Trinity::Containers::MapGetValuePtr(_areaTriggerCreateProperties, createPropertiesId);
359 if (!createProperties)
360 {
361 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties_orbit` reference invalid AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})", createPropertiesId.Id, uint32(createPropertiesId.IsCustom));
362 continue;
363 }
364
365 AreaTriggerOrbitInfo& orbit = createProperties->Movement.emplace<AreaTriggerOrbitInfo>();
366
367 orbit.ExtraTimeForBlending = circularMovementInfoFields[2].GetInt32();
368
369#define VALIDATE_AND_SET_FLOAT(Float, Value) \
370 orbit.Float = Value; \
371 if (!std::isfinite(orbit.Float)) \
372 { \
373 TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties_orbit` has listed areatrigger (AreaTriggerCreatePropertiesId: {}, IsCustom: {}) with invalid " #Float " ({}), set to 0!", \
374 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), orbit.Float); \
375 orbit.Float = 0.0f; \
376 }
377
378 VALIDATE_AND_SET_FLOAT(Radius, circularMovementInfoFields[3].GetFloat());
379 VALIDATE_AND_SET_FLOAT(BlendFromRadius, circularMovementInfoFields[4].GetFloat());
380 VALIDATE_AND_SET_FLOAT(InitialAngle, circularMovementInfoFields[5].GetFloat());
381 VALIDATE_AND_SET_FLOAT(ZOffset, circularMovementInfoFields[6].GetFloat());
382
383#undef VALIDATE_AND_SET_FLOAT
384
385 orbit.CounterClockwise = circularMovementInfoFields[7].GetBool();
386 orbit.CanLoop = circularMovementInfoFields[8].GetBool();
387 }
388 while (circularMovementInfos->NextRow());
389 }
390 else
391 {
392 TC_LOG_INFO("server.loading", ">> Loaded 0 AreaTrigger templates circular movement infos. DB table `areatrigger_create_properties_orbit` is empty.");
393 }
394
395 TC_LOG_INFO("server.loading", ">> Loaded {} spell areatrigger templates in {} ms.", _areaTriggerTemplateStore.size(), GetMSTimeDiffToNow(oldMSTime));
396}
397
399{
400 // build single time for check spawnmask
401 std::unordered_map<uint32, std::set<Difficulty>> spawnMasks;
402 for (MapDifficultyEntry const* mapDifficulty : sMapDifficultyStore)
403 spawnMasks[mapDifficulty->MapID].insert(Difficulty(mapDifficulty->DifficultyID));
404
405 uint32 oldMSTime = getMSTime();
406 // 0 1 2 3 4 5 6 7 8 9 10 11 12
407 if (QueryResult templates = WorldDatabase.Query("SELECT SpawnId, AreaTriggerCreatePropertiesId, IsCustom, MapId, SpawnDifficulties, PosX, PosY, PosZ, Orientation, PhaseUseFlags, PhaseId, PhaseGroup, ScriptName FROM `areatrigger`"))
408 {
409 do
410 {
411 Field* fields = templates->Fetch();
412
413 ObjectGuid::LowType spawnId = fields[0].GetUInt64();
414 AreaTriggerCreatePropertiesId createPropertiesId = { fields[1].GetUInt32(), fields[2].GetBool() };
415 WorldLocation location(fields[3].GetUInt32(), fields[5].GetFloat(), fields[6].GetFloat(), fields[7].GetFloat(), fields[8].GetFloat());
416
417 AreaTriggerCreateProperties const* createProperties = GetAreaTriggerCreateProperties(createPropertiesId);
418 if (!createProperties)
419 {
420 TC_LOG_ERROR("sql.sql", "Table `areatrigger` has listed AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) that doesn't exist for SpawnId {}",
421 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), spawnId);
422 continue;
423 }
424
425 if (createProperties->Flags != AreaTriggerCreatePropertiesFlag::None)
426 {
427 TC_LOG_ERROR("sql.sql", "Table `areatrigger` has listed AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with non - zero flags",
428 createPropertiesId.Id, uint32(createPropertiesId.IsCustom));
429 continue;
430 }
431
432 if (createProperties->ScaleCurveId || createProperties->MorphCurveId || createProperties->FacingCurveId || createProperties->MoveCurveId)
433 {
434 TC_LOG_ERROR("sql.sql", "Table `areatrigger` has listed AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with curve values",
435 createPropertiesId.Id, uint32(createPropertiesId.IsCustom));
436 continue;
437 }
438
439 if (createProperties->TimeToTargetScale)
440 {
441 TC_LOG_ERROR("sql.sql", "Table `areatrigger` has listed AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with time to target values",
442 createPropertiesId.Id, uint32(createPropertiesId.IsCustom));
443 continue;
444 }
445
446 if (!std::holds_alternative<std::monostate>(createProperties->Movement))
447 {
448 std::string_view movementType = std::visit([&]<typename MovementType>(MovementType const&)
449 {
450 if constexpr (std::is_same_v<MovementType, AreaTriggerCreateProperties::SplineInfo>)
451 return "spline"sv;
452 else if constexpr (std::is_same_v<MovementType, AreaTriggerOrbitInfo>)
453 return "orbit"sv;
454 else if constexpr (std::is_same_v<MovementType, std::monostate>)
455 return ""sv;
456 else
457 static_assert(Trinity::dependant_false_v<MovementType>, "Unsupported movement type");
458 }, createProperties->Movement);
459
460 TC_LOG_ERROR("sql.sql", "Table `areatrigger` has listed AreaTriggerCreatePropertiesId (Id: {}, IsCustom: {}) with {}",
461 createPropertiesId.Id, uint32(createPropertiesId.IsCustom), movementType);
462 continue;
463 }
464
465 if (!MapManager::IsValidMapCoord(location))
466 {
467 TC_LOG_ERROR("sql.sql", "Table `areatrigger` has listed an invalid position: SpawnId: {}, Location {}",
468 spawnId, location);
469 continue;
470 }
471
472 std::vector<Difficulty> difficulties = sObjectMgr->ParseSpawnDifficulties(fields[4].GetStringView(), "areatrigger", spawnId, location.GetMapId(), spawnMasks[location.GetMapId()]);
473 if (difficulties.empty())
474 {
475 TC_LOG_DEBUG("sql.sql", "Table `areatrigger` has areatrigger (GUID: {}) that is not spawned in any difficulty, skipped.", spawnId);
476 continue;
477 }
478
479 AreaTriggerSpawn& spawn = _areaTriggerSpawnsBySpawnId[spawnId];
480 spawn.spawnId = spawnId;
481 spawn.mapId = location.GetMapId();
482 spawn.Id = createPropertiesId;
483 spawn.spawnPoint.Relocate(location);
484
485 spawn.phaseUseFlags = fields[9].GetUInt8();
486 spawn.phaseId = fields[10].GetUInt32();
487 spawn.phaseGroup = fields[11].GetUInt32();
488
489 spawn.scriptId = sObjectMgr->GetScriptId(fields[12].GetStringView());
490 spawn.spawnGroupData = sObjectMgr->GetLegacySpawnGroup();
491
492 // Add the trigger to a map::cell map, which is later used by GridLoader to query
494 for (Difficulty difficulty : difficulties)
495 _areaTriggerSpawnsByLocation[{ spawn.mapId, difficulty }][gridCoord.GetId()].insert(spawnId);
496 } while (templates->NextRow());
497 }
498
499 TC_LOG_INFO("server.loading", ">> Loaded {} areatrigger spawns in {} ms.", _areaTriggerSpawnsBySpawnId.size(), GetMSTimeDiffToNow(oldMSTime));
500}
501
503{
504 return Trinity::Containers::MapGetValuePtr(_areaTriggerTemplateStore, areaTriggerId);
505}
506
508{
509 return Trinity::Containers::MapGetValuePtr(_areaTriggerCreateProperties, areaTriggerCreatePropertiesId);
510}
511
513{
514 if (auto* atForMapAndDifficulty = Trinity::Containers::MapGetValuePtr(_areaTriggerSpawnsByLocation, { mapId, difficulty }))
515 return Trinity::Containers::MapGetValuePtr(*atForMapAndDifficulty, gridId);
516
517 return nullptr;
518}
519
521{
522 return Trinity::Containers::MapGetValuePtr(_areaTriggerSpawnsBySpawnId, spawnId);
523}
524
526{
527 static AreaTriggerDataStore instance;
528 return &instance;
529}
#define VALIDATE_AND_SET_CURVE(Curve, Value)
#define VALIDATE_AND_SET_FLOAT(Float, Value)
AreaTriggerCreatePropertiesFlag
AreaTriggerActionTypes
@ AREATRIGGER_ACTION_TELEPORT
@ AREATRIGGER_ACTION_MAX
AreaTriggerFlag
AreaTriggerActionUserTypes
@ AREATRIGGER_ACTION_USER_MAX
DB2Storage< MapDifficultyEntry > sMapDifficultyStore("MapDifficulty.db2", &MapDifficultyLoadInfo::Instance)
DB2Storage< SoundKitEntry > sSoundKitStore("SoundKit.db2", &SoundKitLoadInfo::Instance)
AreaTriggerShapeType
Definition DBCEnums.h:196
AreaTriggerActionSetFlag
Definition DBCEnums.h:175
Difficulty
Definition DBCEnums.h:935
@ DIFFICULTY_NONE
Definition DBCEnums.h:936
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint32_t uint32
Definition Define.h:154
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:176
#define sObjectMgr
Definition ObjectMgr.h:1873
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
#define DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(result_type, fields_list)
#define sSpellMgr
Definition SpellMgr.h:812
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
EnumFlag< AreaTriggerCreatePropertiesFlag > Flags
AreaTriggerCreatePropertiesId Id
TaggedPosition< Position::XYZ > RollPitchYaw
std::variant< std::monostate, SplineInfo, AreaTriggerOrbitInfo > Movement
AreaTriggerTemplate const * Template
Optional< TaggedPosition< Position::XYZ > > TargetRollPitchYaw
AreaTriggerTemplate const * GetAreaTriggerTemplate(AreaTriggerId const &areaTriggerId) const
AreaTriggerCreateProperties const * GetAreaTriggerCreateProperties(AreaTriggerCreatePropertiesId const &areaTriggerCreatePropertiesId) const
Trinity::Containers::FlatSet< ObjectGuid::LowType > const * GetAreaTriggersForMapAndGrid(uint32 mapId, Difficulty difficulty, uint32 gridId) const
AreaTriggerSpawn const * GetAreaTriggerSpawn(ObjectGuid::LowType spawnId) const
static AreaTriggerDataStore * Instance()
EnumFlag< AreaTriggerActionSetFlag > ActionSetFlags
std::vector< AreaTriggerAction > Actions
EnumFlag< AreaTriggerFlag > Flags
Class used to access individual fields of database query result.
Definition Field.h:94
uint64 GetUInt64() const noexcept
Definition Field.cpp:71
bool GetBool() const noexcept
Definition Field.h:102
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
int32 GetInt32() const noexcept
Definition Field.cpp:64
static bool IsValidMapCoord(uint32 mapid, float x, float y)
Definition MapManager.h:83
uint64 LowType
Definition ObjectGuid.h:321
constexpr uint32 GetMapId() const
Definition Position.h:216
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
constexpr GridCoord ComputeGridCoord(float x, float y)
AreaTriggerActionTypes ActionType
AreaTriggerActionUserTypes TargetType
std::vector< TaggedPosition< Position::XY > > PolygonVerticesTarget
std::vector< TaggedPosition< Position::XY > > PolygonVertices
std::variant< Sphere, Box, Polygon, Cylinder, Disk, BoundedPlane > Data
AreaTriggerCreatePropertiesId Id
constexpr uint32 GetId() const
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr void Relocate(float x, float y)
Definition Position.h:74
uint32 scriptId
Definition SpawnData.h:144
uint8 phaseUseFlags
Definition SpawnData.h:137
uint32 phaseId
Definition SpawnData.h:138
Position spawnPoint
Definition SpawnData.h:136
uint32 phaseGroup
Definition SpawnData.h:139
SpawnGroupTemplateData const * spawnGroupData
Definition SpawnData.h:124
uint64 spawnId
Definition SpawnData.h:121
Position Pos
Definition Position.h:254
constexpr void UpdateData(std::span< V, Extent > data) noexcept
Definition Hash.h:85
std::size_t operator()(AreaTriggerId const &value) const noexcept