diff --git a/README.md b/README.md index 84675eb0414..789e2ebd995 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,12 @@ ## Build Status -master | 3.3.5 | wotlk_classic +master | 3.3.5 | cata_classic :------------: | :------------: | :------------: -[![master Build Status](https://circleci.com/gh/TrinityCore/TrinityCore/tree/master.svg?style=shield)](https://circleci.com/gh/TrinityCore/TrinityCore/tree/master) | [![3.3.5 Build Status](https://circleci.com/gh/TrinityCore/TrinityCore/tree/3.3.5.svg?style=shield)](https://circleci.com/gh/TrinityCore/TrinityCore/tree/3.3.5) | [![wotlk_classic Build Status](https://circleci.com/gh/TrinityCore/TrinityCore/tree/wotlk_classic.svg?style=shield)](https://circleci.com/gh/TrinityCore/TrinityCore/tree/wotlk_classic) -[![master Build status](https://ci.appveyor.com/api/projects/status/54d0u1fxe50ad80o/branch/master?svg=true)](https://ci.appveyor.com/project/DDuarte/trinitycore/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/54d0u1fxe50ad80o/branch/3.3.5?svg=true)](https://ci.appveyor.com/project/DDuarte/trinitycore/branch/3.3.5) | [![Build status](https://ci.appveyor.com/api/projects/status/54d0u1fxe50ad80o/branch/wotlk_classic?svg=true)](https://ci.appveyor.com/project/DDuarte/trinitycore/branch/wotlk_classic) -[![master GCC Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/gcc-build.yml/badge.svg?branch=master&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3Amaster+event%3Apush) | [![3.3.5 GCC Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/gcc-build.yml/badge.svg?branch=3.3.5&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3A3.3.5+event%3Apush) | [![wotlk_classic GCC Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/gcc-build.yml/badge.svg?branch=wotlk_classic&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3Awotlk_classic+event%3Apush) +[![master Build Status](https://circleci.com/gh/TrinityCore/TrinityCore/tree/master.svg?style=shield)](https://circleci.com/gh/TrinityCore/TrinityCore/tree/master) | [![3.3.5 Build Status](https://circleci.com/gh/TrinityCore/TrinityCore/tree/3.3.5.svg?style=shield)](https://circleci.com/gh/TrinityCore/TrinityCore/tree/3.3.5) | [![cata_classic Build Status](https://circleci.com/gh/TrinityCore/TrinityCore/tree/cata_classic.svg?style=shield)](https://circleci.com/gh/TrinityCore/TrinityCore/tree/cata_classic) +[![master Build status](https://ci.appveyor.com/api/projects/status/54d0u1fxe50ad80o/branch/master?svg=true)](https://ci.appveyor.com/project/DDuarte/trinitycore/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/54d0u1fxe50ad80o/branch/3.3.5?svg=true)](https://ci.appveyor.com/project/DDuarte/trinitycore/branch/3.3.5) | [![Build status](https://ci.appveyor.com/api/projects/status/54d0u1fxe50ad80o/branch/cata_classic?svg=true)](https://ci.appveyor.com/project/DDuarte/trinitycore/branch/cata_classic) +[![master GCC Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/gcc-build.yml/badge.svg?branch=master&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3Amaster+event%3Apush) | [![3.3.5 GCC Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/gcc-build.yml/badge.svg?branch=3.3.5&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3A3.3.5+event%3Apush) | [![cata_classic GCC Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/gcc-build.yml/badge.svg?branch=cata_classic&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3Acata_classic+event%3Apush) +[![master macOS arm64 Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/macos-arm-build.yml/badge.svg?branch=master&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3Amaster+event%3Apush) | | [![cata_classic macOS arm64 Build status](https://github.com/TrinityCore/TrinityCore/actions/workflows/macos-arm-build.yml/badge.svg?branch=cata_classic&event=push)](https://github.com/TrinityCore/TrinityCore/actions?query=workflow%3AGCC+branch%3Acata_classic+event%3Apush) [![Coverity Scan Build Status](https://scan.coverity.com/projects/435/badge.svg)](https://scan.coverity.com/projects/435) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/4656/badge.svg)](https://scan.coverity.com/projects/4656) | ## Introduction diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 5612d8f3b89..12faae6da4d 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1340,7 +1340,7 @@ DROP TABLE IF EXISTS `characters`; CREATE TABLE `characters` ( `guid` int unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier', `account` int unsigned NOT NULL DEFAULT '0' COMMENT 'Account Identifier', - `name` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, + `name` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, `race` tinyint unsigned NOT NULL DEFAULT '0', `class` tinyint unsigned NOT NULL DEFAULT '0', `gender` tinyint unsigned NOT NULL DEFAULT '0', @@ -1415,9 +1415,9 @@ CREATE TABLE `characters` ( `deleteInfos_Name` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `deleteDate` int unsigned DEFAULT NULL, PRIMARY KEY (`guid`), + UNIQUE KEY `idx_name` (`name`), KEY `idx_account` (`account`), - KEY `idx_online` (`online`), - KEY `idx_name` (`name`) + KEY `idx_online` (`online`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Player System'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -2686,7 +2686,8 @@ INSERT INTO `updates` VALUES ('2024_01_21_00_characters.sql','4D27D8DAC9F78795DB6938B54F32502EF8D8AAE6','ARCHIVED','2024-01-21 11:38:22',0), ('2024_02_05_00_characters.sql','1777CBCA822AD85777DA4A390DF7AAF41AF68EBD','ARCHIVED','2024-02-05 12:17:19',0), ('2024_04_10_00_characters.sql','E0D6E19ACE6759332402FA27C23B0F7745C49742','ARCHIVED','2024-04-10 16:07:02',0), -('2024_08_17_00_characters.sql','08705FBCB8504E8B1009FDAF955F56D734FAD782','ARCHIVED','2024-08-17 22:26:12',0); +('2024_08_17_00_characters.sql','08705FBCB8504E8B1009FDAF955F56D734FAD782','ARCHIVED','2024-08-17 22:26:12',0), +('2024_10_03_00_characters.sql','408249A6992999A36EB94089D184972E8E0767A3','RELEASED','2024-10-03 11:10:18',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/3.3.5/2024_10_03_00_characters.sql b/sql/updates/characters/3.3.5/2024_10_03_00_characters.sql new file mode 100644 index 00000000000..7b5a6fcf357 --- /dev/null +++ b/sql/updates/characters/3.3.5/2024_10_03_00_characters.sql @@ -0,0 +1,29 @@ +-- append guid as hex to characters who have duplicate names in database except the one with lowest guid (assumed to have been created first) +-- and flag them for rename +CREATE TEMPORARY TABLE `characters_to_rename` SELECT + c2.`guid` + FROM + ( + SELECT + c1.`name` AS `name`, + MIN(c1.`guid`) AS originalGuid + FROM + `characters` c1 + WHERE + LENGTH(c1.`name`) > 0 + GROUP BY + 1 + HAVING + COUNT(*) > 1 + ) c3 + INNER JOIN `characters` c2 ON c3.`name` = c2.`name` + WHERE + c2.guid <> c3.originalGuid; + +UPDATE `characters` SET `name` = CONCAT(SUBSTRING(`name` FROM 1 FOR 12 - LENGTH(CONV(`guid`, 10, 16))), CONV(`guid`, 10, 16)), `at_login` = `at_login` | 1 WHERE `guid` IN (SELECT `guid` FROM `characters_to_rename`); + +-- recreate name index with unique constraint +ALTER TABLE `characters` DROP INDEX `idx_name`; +ALTER TABLE `characters` MODIFY COLUMN `name` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL AFTER `account`; +UPDATE `characters` SET `name` = NULL WHERE `name` = ''; +ALTER TABLE `characters` ADD UNIQUE INDEX `idx_name` (`name` ASC); diff --git a/sql/updates/world/3.3.5/2024_10_02_00_world.sql b/sql/updates/world/3.3.5/2024_10_02_00_world.sql new file mode 100644 index 00000000000..7c5cc2b4193 --- /dev/null +++ b/sql/updates/world/3.3.5/2024_10_02_00_world.sql @@ -0,0 +1,10 @@ +-- +DELETE FROM `prospecting_loot_template` WHERE `Entry`=10620 AND `Reference`=13001; +DELETE FROM `prospecting_loot_template` WHERE `Entry`=10620 AND `Item` IN (21929,23077,23079,23107,23112,23117); +INSERT INTO `prospecting_loot_template` (`Entry`,`Item`,`Reference`,`Chance`,`QuestRequired`,`LootMode`,`GroupId`,`MinCount`,`MaxCount`,`Comment`) VALUES +(10620,21929,0,0,0,1,1,1,2,NULL), +(10620,23077,0,0,0,1,1,1,2,NULL), +(10620,23079,0,0,0,1,1,1,2,NULL), +(10620,23107,0,0,0,1,1,1,2,NULL), +(10620,23112,0,0,0,1,1,1,2,NULL), +(10620,23117,0,0,0,1,1,1,2,NULL); diff --git a/sql/updates/world/3.3.5/2024_10_05_00_world_2022_12_27_01_world.sql b/sql/updates/world/3.3.5/2024_10_05_00_world_2022_12_27_01_world.sql new file mode 100644 index 00000000000..5e0f6fd45c8 --- /dev/null +++ b/sql/updates/world/3.3.5/2024_10_05_00_world_2022_12_27_01_world.sql @@ -0,0 +1,8 @@ +-- +DELETE FROM `trinity_string` WHERE `entry`=5089; +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(5089,'Template StringID: %.*s\Spawn StringID: %.*s\nScript StringID: %.*s'); + +ALTER TABLE `creature` ADD `StringId` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL AFTER ScriptName; + +ALTER TABLE `creature_template` ADD `StringId` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL AFTER ScriptName; diff --git a/sql/updates/world/3.3.5/2024_10_05_01_world_2023_07_30_00_world.sql b/sql/updates/world/3.3.5/2024_10_05_01_world_2023_07_30_00_world.sql new file mode 100644 index 00000000000..0b4686a7e7d --- /dev/null +++ b/sql/updates/world/3.3.5/2024_10_05_01_world_2023_07_30_00_world.sql @@ -0,0 +1,3 @@ +ALTER TABLE `gameobject` ADD `StringId` varchar(64) AFTER `ScriptName`; + +ALTER TABLE `gameobject_template` ADD `StringId` varchar(64) AFTER `ScriptName`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 35c9d4d5537..4e576e207a6 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -373,7 +373,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_ALL_GM_TICKETS, "TRUNCATE TABLE gm_ticket", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_SPELL_TALENTS, "DELETE FROM character_talent WHERE spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_SPELL_SPELLS, "DELETE FROM character_spell WHERE spell = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = NULL, account = 0 WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_RESTORE_DELETE_INFO, "UPDATE characters SET name = ?, account = ?, deleteDate = NULL, deleteInfos_Name = NULL, deleteInfos_Account = NULL WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ZONE, "UPDATE characters SET zone = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_LEVEL, "UPDATE characters SET level = ?, xp = 0 WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 372f64a273c..b28abd0e7fc 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -77,7 +77,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, type, type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, type, type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 1616d3e5787..48cd8e63888 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -385,6 +385,11 @@ inline Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, return source->FindNearestCreature(entry, maxSearchRange, alive); } +inline Creature* GetClosestCreatureWithOptions(WorldObject* source, float maxSearchRange, FindCreatureOptions const& options) +{ + return source->FindNearestCreatureWithOptions(maxSearchRange, options); +} + inline GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool spawnedOnly = true) { return source->FindNearestGameObject(entry, maxSearchRange, spawnedOnly); @@ -396,6 +401,12 @@ inline void GetCreatureListWithEntryInGrid(Container& container, WorldObject* so source->GetCreatureListWithEntryInGrid(container, entry, maxSearchRange); } +template +inline void GetCreatureListWithOptionsInGrid(Container& container, WorldObject* source, float maxSearchRange, FindCreatureOptions const& options) +{ + source->GetCreatureListWithOptionsInGrid(container, maxSearchRange, options); +} + template inline void GetGameObjectListWithEntryInGrid(Container& container, WorldObject* source, uint32 entry, float maxSearchRange) { diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 0cfea7c0c30..ce1e8053f57 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1216,7 +1216,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!summoner) break; - bool personalSpawn = flags.HasFlag(SmartActionSummonCreatureFlags::PersonalSpawn); + ObjectGuid privateObjectOwner; + if (flags.HasFlag(SmartActionSummonCreatureFlags::PersonalSpawn)) + privateObjectOwner = summoner->IsPrivateObject() ? summoner->GetPrivateObjectOwner() : summoner->GetGUID(); uint32 spawnsCount = std::max(e.action.summonCreature.count, 1u); float x, y, z, o; @@ -1229,7 +1231,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u o += e.target.o; for (uint32 counter = 0; counter < spawnsCount; counter++) { - if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), personalSpawn)) + if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), privateObjectOwner)) if (e.action.summonCreature.attackInvoker) summon->AI()->AttackStart(target->ToUnit()); } @@ -1240,7 +1242,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (uint32 counter = 0; counter < spawnsCount; counter++) { - if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, e.target.x, e.target.y, e.target.z, e.target.o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), personalSpawn)) + if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, e.target.x, e.target.y, e.target.z, e.target.o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), privateObjectOwner)) if (unit && e.action.summonCreature.attackInvoker) summon->AI()->AttackStart(unit); } diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 50ad9a8e673..502031712c4 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -374,21 +374,14 @@ void ThreatManager::AddThreat(Unit* target, float amount, SpellInfo const* spell return; amount = 0.0f; } - else if (TempSummon* tempSummonVictim = target->ToTempSummon()) + + // If victim is personal spawn, redirect all aggro to summoner + if (target->IsPrivateObject() && (!GetOwner()->IsPrivateObject() || !GetOwner()->CheckPrivateObjectOwnerVisibility(target))) { - if (tempSummonVictim->IsVisibleBySummonerOnly()) + if (Unit* privateObjectOwner = ObjectAccessor::GetUnit(*GetOwner(), target->GetPrivateObjectOwner())) { - if (Unit* tempSummonSummoner = tempSummonVictim->GetSummonerUnit()) - { - // Personnal Spawns from same summoner can aggro each other - if (!_owner->ToTempSummon() || - !_owner->ToTempSummon()->IsVisibleBySummonerOnly() || - tempSummonVictim->GetSummonerGUID() != GetOwner()->ToTempSummon()->GetSummonerGUID()) - { - AddThreat(tempSummonSummoner, amount, spell, ignoreModifiers, ignoreRedirects); - amount = 0.0f; - } - } + AddThreat(privateObjectOwner, amount, spell, ignoreModifiers, ignoreRedirects); + amount = 0.0f; } } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 5f730c9c996..56cfb3713e8 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -251,9 +251,12 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) } Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootRecipient(), m_lootRecipientGroup(0), _pickpocketLootRestore(0), - m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_ignoreCorpseDecayRatio(false), m_wanderDistance(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), - m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_cannotReachTarget(false), m_cannotReachTimer(0), - m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), + m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_ignoreCorpseDecayRatio(false), m_wanderDistance(0.0f), + m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), + m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), + m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_cannotReachTarget(false), m_cannotReachTimer(0), + m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(), + m_creatureInfo(nullptr), m_creatureData(nullptr), m_stringIds(), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0), _regenerateHealth(true), _regenerateHealthLock(false), _isMissingCanSwimFlagOutOfCombat(false) { @@ -635,6 +638,8 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, //We must update last scriptId or it looks like we reloaded a script, breaking some things such as gossip temporarily LastUsedScriptID = GetScriptId(); + m_stringIds[AsUnderlyingType(StringIdType::Template)] = &cInfo->StringId; + return true; } @@ -1685,6 +1690,8 @@ bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, // checked at creature_template loading m_defaultMovementType = MovementGeneratorType(data->movementType); + m_stringIds[AsUnderlyingType(StringIdType::Spawn)] = &data->StringId; + if (addToMap && !GetMap()->AddToMap(this)) return false; return true; @@ -2772,6 +2779,34 @@ uint32 Creature::GetScriptId() const return ASSERT_NOTNULL(sObjectMgr->GetCreatureTemplate(GetEntry()))->ScriptID; } +void Creature::InheritStringIds(Creature const* parent) +{ + // copy references to stringIds from template and spawn + m_stringIds = parent->m_stringIds; + + // then copy script stringId, not just its reference + SetScriptStringId(std::string(parent->GetStringId(StringIdType::Script))); +} + +bool Creature::HasStringId(std::string_view id) const +{ + return std::ranges::any_of(m_stringIds, [id](std::string const* stringId) { return stringId && *stringId == id; }); +} + +void Creature::SetScriptStringId(std::string id) +{ + if (!id.empty()) + { + m_scriptStringId.emplace(std::move(id)); + m_stringIds[AsUnderlyingType(StringIdType::Script)] = &*m_scriptStringId; + } + else + { + m_scriptStringId.reset(); + m_stringIds[AsUnderlyingType(StringIdType::Script)] = nullptr; + } +} + VendorItemData const* Creature::GetVendorItems() const { return sObjectMgr->GetNpcVendorItemList(GetEntry()); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 8a65ca53724..1c1504d74e3 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -198,6 +198,10 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma std::string const& GetAIName() const; std::string GetScriptName() const; uint32 GetScriptId() const; + void InheritStringIds(Creature const* parent); + bool HasStringId(std::string_view id) const; + void SetScriptStringId(std::string id); + std::string_view GetStringId(StringIdType type) const { return m_stringIds[size_t(type)] ? std::string_view(*m_stringIds[size_t(type)]) : std::string_view(); } // override WorldObject function for proper name localization std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override; @@ -421,6 +425,8 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma CreatureTemplate const* m_creatureInfo; // Can differ from sObjectMgr->GetCreatureTemplate(GetEntry()) in difficulty mode > 0 CreatureData const* m_creatureData; + std::array m_stringIds; + Optional m_scriptStringId; uint16 m_LootMode; // Bitmask (default: LOOT_MODE_DEFAULT) that determines what loot will be lootable diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 325bc22ab26..f4e6bdb1968 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -349,6 +349,7 @@ struct TC_GAME_API CreatureTemplate uint32 SpellSchoolImmuneMask; uint32 flags_extra; uint32 ScriptID; + std::string StringId; WorldPacket QueryData[TOTAL_LOCALES]; uint32 GetRandomValidModelId() const; uint32 GetFirstValidModelId() const; diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index ccd95f38583..2afc0f90307 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -28,7 +28,7 @@ TempSummon::TempSummon(SummonPropertiesEntry const* properties, WorldObject* owner, bool isWorldObject) : Creature(isWorldObject), m_Properties(properties), m_type(TEMPSUMMON_MANUAL_DESPAWN), -m_timer(0), m_lifetime(0), m_canFollowOwner(true), m_visibleBySummonerOnly(false) +m_timer(0), m_lifetime(0), m_canFollowOwner(true) { if (owner) m_summonerGUID = owner->GetGUID(); diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index 24aff599f97..60a55f96ce4 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -54,9 +54,6 @@ class TC_GAME_API TempSummon : public Creature uint32 GetTimer() const { return m_timer; } bool CanFollowOwner() const { return m_canFollowOwner; } void SetCanFollowOwner(bool can) { m_canFollowOwner = can; } - void SetVisibleBySummonerOnly(bool visibleBySummonerOnly) { m_visibleBySummonerOnly = visibleBySummonerOnly; } - bool IsVisibleBySummonerOnly() const { return m_visibleBySummonerOnly; } - SummonPropertiesEntry const* const m_Properties; std::string GetDebugInfo() const override; @@ -66,7 +63,6 @@ class TC_GAME_API TempSummon : public Creature uint32 m_lifetime; ObjectGuid m_summonerGUID; bool m_canFollowOwner; - bool m_visibleBySummonerOnly; }; class TC_GAME_API Minion : public TempSummon diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index d893a357b85..db28b515d04 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -108,7 +108,7 @@ QuaternionData QuaternionData::fromEulerAnglesZYX(float Z, float Y, float X) } GameObject::GameObject() : WorldObject(false), MapObject(), - m_model(nullptr), m_goValue(), m_AI(nullptr), m_respawnCompatibilityMode(false) + m_model(nullptr), m_goValue(), m_stringIds(), m_AI(nullptr), m_respawnCompatibilityMode(false) { m_objectType |= TYPEMASK_GAMEOBJECT; m_objectTypeId = TYPEID_GAMEOBJECT; @@ -417,6 +417,9 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u } LastUsedScriptID = GetGOInfo()->ScriptId; + + m_stringIds[AsUnderlyingType(StringIdType::Template)] = &goinfo->StringId; + AIM_Initialize(); // Initialize loot duplicate count depending on raid difficulty @@ -1142,6 +1145,8 @@ bool GameObject::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap m_goData = data; + m_stringIds[AsUnderlyingType(StringIdType::Spawn)] = &data->StringId; + if (addToMap && !GetMap()->AddToMap(this)) return false; @@ -2270,6 +2275,34 @@ uint32 GameObject::GetScriptId() const return GetGOInfo()->ScriptId; } +void GameObject::InheritStringIds(GameObject const* parent) +{ + // copy references to stringIds from template and spawn + m_stringIds = parent->m_stringIds; + + // then copy script stringId, not just its reference + SetScriptStringId(std::string(parent->GetStringId(StringIdType::Script))); +} + +bool GameObject::HasStringId(std::string_view id) const +{ + return std::ranges::any_of(m_stringIds, [id](std::string const* stringId) { return stringId && *stringId == id; }); +} + +void GameObject::SetScriptStringId(std::string id) +{ + if (!id.empty()) + { + m_scriptStringId.emplace(std::move(id)); + m_stringIds[AsUnderlyingType(StringIdType::Script)] = &*m_scriptStringId; + } + else + { + m_scriptStringId.reset(); + m_stringIds[AsUnderlyingType(StringIdType::Script)] = nullptr; + } +} + // overwrite WorldObject function for proper name localization std::string const & GameObject::GetNameForLocaleIdx(LocaleConstant loc_idx) const { diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index f45682405b2..a73e6ce8fff 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -270,10 +270,15 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject void SetRespawnCompatibilityMode(bool mode = true) { m_respawnCompatibilityMode = mode; } bool GetRespawnCompatibilityMode() {return m_respawnCompatibilityMode; } + std::string const& GetAIName() const; uint32 GetScriptId() const; GameObjectAI* AI() const { return m_AI; } - std::string const& GetAIName() const; + void InheritStringIds(GameObject const* parent); + bool HasStringId(std::string_view id) const; + void SetScriptStringId(std::string id); + std::string_view GetStringId(StringIdType type) const { return m_stringIds[size_t(type)] ? std::string_view(*m_stringIds[size_t(type)]) : std::string_view(); } + void SetDisplayId(uint32 displayid); uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); } @@ -339,6 +344,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject GameObjectTemplateAddon const* m_goTemplateAddon; GameObjectData const* m_goData; GameObjectValue m_goValue; + std::array m_stringIds; + Optional m_scriptStringId; int64 m_packedRotation; QuaternionData m_localRotation; diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h index 40eda9ce862..a4e4a4bdce2 100644 --- a/src/server/game/Entities/GameObject/GameObjectData.h +++ b/src/server/game/Entities/GameObject/GameObjectData.h @@ -420,6 +420,7 @@ struct GameObjectTemplate std::string AIName; uint32 ScriptId; + std::string StringId; WorldPacket QueryData[TOTAL_LOCALES]; // helpers diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 059fb6ebcec..74cfa6e9bb6 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1542,6 +1542,22 @@ float WorldObject::GetSightRange(WorldObject const* target) const return 0.0f; } +bool WorldObject::CheckPrivateObjectOwnerVisibility(WorldObject const* seer) const +{ + if (!IsPrivateObject()) + return true; + + // Owner of this private object + if (_privateObjectOwner == seer->GetGUID()) + return true; + + // Another private object of the same owner + if (_privateObjectOwner == seer->GetPrivateObjectOwner()) + return true; + + return false; +} + bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool implicitDetect, bool distanceCheck, bool checkAlert) const { if (this == obj) @@ -1553,6 +1569,9 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool implicitDetect, bo if (obj->IsAlwaysVisibleFor(this) || CanAlwaysSee(obj)) return true; + if (!obj->CheckPrivateObjectOwnerVisibility(this)) + return false; + bool corpseVisibility = false; if (distanceCheck) { @@ -1582,15 +1601,8 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool implicitDetect, bo WorldObject const* viewpoint = this; if (Player const* player = ToPlayer()) - { viewpoint = player->GetViewpoint(); - if (Creature const* creature = obj->ToCreature()) - if (TempSummon const* tempSummon = creature->ToTempSummon()) - if (tempSummon->IsVisibleBySummonerOnly() && GetGUID() != tempSummon->GetSummonerGUID()) - return false; - } - if (!viewpoint) viewpoint = this; @@ -1858,7 +1870,7 @@ void WorldObject::AddObjectToRemoveList() map->AddObjectToRemoveList(this); } -TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= nullptr*/, uint32 duration /*= 0*/, WorldObject* summoner /*= nullptr*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/, bool visibleBySummonerOnly /*= false*/) +TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= nullptr*/, uint32 duration /*= 0*/, WorldObject* summoner /*= nullptr*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/, ObjectGuid privateObjectOwner /*= ObjectGuid::Empty*/) { uint32 mask = UNIT_MASK_SUMMON; if (properties) @@ -1946,7 +1958,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert summon->InitStats(duration); - summon->SetVisibleBySummonerOnly(visibleBySummonerOnly); + summon->SetPrivateObjectOwner(privateObjectOwner); AddToMap(summon->ToCreature()); summon->InitSummon(); @@ -1998,11 +2010,11 @@ void WorldObject::ClearZoneScript() m_zoneScript = nullptr; } -TempSummon* WorldObject::SummonCreature(uint32 entry, Position const& pos, TempSummonType despawnType /*= TEMPSUMMON_MANUAL_DESPAWN*/, Milliseconds despawnTime /*= 0s*/, uint32 /*vehId = 0*/, uint32 spellId /*= 0*/, bool visibleBySummonerOnly /*= false*/) +TempSummon* WorldObject::SummonCreature(uint32 entry, Position const& pos, TempSummonType despawnType /*= TEMPSUMMON_MANUAL_DESPAWN*/, Milliseconds despawnTime /*= 0s*/, uint32 vehId /*= 0*/, uint32 spellId /*= 0*/, ObjectGuid privateObjectOwner /*= ObjectGuid::Empty*/) { if (Map* map = FindMap()) { - if (TempSummon* summon = map->SummonCreature(entry, pos, nullptr, despawnTime.count(), this, spellId, 0, visibleBySummonerOnly)) + if (TempSummon* summon = map->SummonCreature(entry, pos, nullptr, despawnTime.count(), this, spellId, vehId, privateObjectOwner)) { summon->SetTempSummonType(despawnType); return summon; @@ -2012,13 +2024,13 @@ TempSummon* WorldObject::SummonCreature(uint32 entry, Position const& pos, TempS return nullptr; } -TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float o /*= 0*/, TempSummonType despawnType /*= TEMPSUMMON_MANUAL_DESPAWN*/, Milliseconds despawnTime /*= 0s*/, bool visibleBySummonerOnly /*= false*/) +TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float o /*= 0*/, TempSummonType despawnType /*= TEMPSUMMON_MANUAL_DESPAWN*/, Milliseconds despawnTime /*= 0s*/, ObjectGuid privateObjectOwner /*= ObjectGuid::Empty*/) { if (!x && !y && !z) GetClosePoint(x, y, z, GetCombatReach()); if (!o) o = GetOrientation(); - return SummonCreature(id, { x,y,z,o }, despawnType, despawnTime, 0, 0, visibleBySummonerOnly); + return SummonCreature(id, { x,y,z,o }, despawnType, despawnTime, 0, 0, privateObjectOwner); } GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, QuaternionData const& rot, Seconds respawnTime, GOSummonType summonType) @@ -2114,6 +2126,19 @@ Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive return creature; } +Creature* WorldObject::FindNearestCreatureWithOptions(float range, FindCreatureOptions const& options) const +{ + Creature* creature = nullptr; + Trinity::NearestCheckCustomizer checkCustomizer(*this, range); + Trinity::CreatureWithOptionsInObjectRangeCheck checker(*this, checkCustomizer, options); + Trinity::CreatureLastSearcher searcher(this, creature, checker); + if (options.IgnorePhases) + searcher.i_phaseMask = PHASEMASK_ANYWHERE; + + Cell::VisitAllObjects(this, searcher, range); + return creature; +} + GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range, bool spawnedOnly) const { GameObject* go = nullptr; @@ -2123,6 +2148,19 @@ GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range, bool s return go; } +GameObject* WorldObject::FindNearestGameObjectWithOptions(float range, FindGameObjectOptions const& options) const +{ + GameObject* go = nullptr; + Trinity::NearestCheckCustomizer checkCustomizer(*this, range); + Trinity::GameObjectWithOptionsInObjectRangeCheck checker(*this, checkCustomizer, options); + Trinity::GameObjectLastSearcher searcher(this, go, checker); + if (options.IgnorePhases) + searcher.i_phaseMask = PHASEMASK_ANYWHERE; + + Cell::VisitGridObjects(this, searcher, range); + return go; +} + GameObject* WorldObject::FindNearestUnspawnedGameObject(uint32 entry, float range) const { GameObject* go = nullptr; @@ -3119,6 +3157,18 @@ void WorldObject::GetGameObjectListWithEntryInGrid(Container& gameObjectContaine Cell::VisitGridObjects(this, searcher, maxSearchRange); } +template +void WorldObject::GetGameObjectListWithOptionsInGrid(Container& gameObjectContainer, float maxSearchRange, FindGameObjectOptions const& options) const +{ + Trinity::InRangeCheckCustomizer checkCustomizer(*this, maxSearchRange); + Trinity::GameObjectWithOptionsInObjectRangeCheck check(*this, checkCustomizer, options); + Trinity::GameObjectListSearcher searcher(this, gameObjectContainer, check); + if (options.IgnorePhases) + searcher.i_phaseMask = PHASEMASK_ANYWHERE; + + Cell::VisitGridObjects(this, searcher, maxSearchRange); +} + template void WorldObject::GetCreatureListWithEntryInGrid(Container& creatureContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const { @@ -3127,6 +3177,18 @@ void WorldObject::GetCreatureListWithEntryInGrid(Container& creatureContainer, u Cell::VisitGridObjects(this, searcher, maxSearchRange); } +template +void WorldObject::GetCreatureListWithOptionsInGrid(Container& creatureContainer, float maxSearchRange, FindCreatureOptions const& options) const +{ + Trinity::InRangeCheckCustomizer checkCustomizer(*this, maxSearchRange); + Trinity::CreatureWithOptionsInObjectRangeCheck check(*this, checkCustomizer, options); + Trinity::CreatureListSearcher searcher(this, creatureContainer, check); + if (options.IgnorePhases) + searcher.i_phaseMask = PHASEMASK_ANYWHERE; + + Cell::VisitGridObjects(this, searcher, maxSearchRange); +} + template void WorldObject::GetPlayerListInGrid(Container& playerContainer, float maxSearchRange, bool alive /*= true*/) const { @@ -3580,10 +3642,18 @@ template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::lis template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector&, uint32, float) const; +template TC_GAME_API void WorldObject::GetGameObjectListWithOptionsInGrid(std::list&, float, FindGameObjectOptions const&) const; +template TC_GAME_API void WorldObject::GetGameObjectListWithOptionsInGrid(std::deque&, float, FindGameObjectOptions const&) const; +template TC_GAME_API void WorldObject::GetGameObjectListWithOptionsInGrid(std::vector&, float, FindGameObjectOptions const&) const; + template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::list&, uint32, float) const; template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::deque&, uint32, float) const; template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::vector&, uint32, float) const; +template TC_GAME_API void WorldObject::GetCreatureListWithOptionsInGrid(std::list&, float, FindCreatureOptions const&) const; +template TC_GAME_API void WorldObject::GetCreatureListWithOptionsInGrid(std::deque&,float, FindCreatureOptions const&) const; +template TC_GAME_API void WorldObject::GetCreatureListWithOptionsInGrid(std::vector&, float, FindCreatureOptions const&) const; + template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::list&, float, bool) const; template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::deque&, float, bool) const; template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::vector&, float, bool) const; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 9dca2efa026..192cff8495e 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -296,6 +296,68 @@ class FlaggedValuesArray32 T_FLAGS m_flags; }; +struct FindCreatureOptions +{ + FindCreatureOptions() = default; + + FindCreatureOptions& SetCreatureId(uint32 creatureId) { CreatureId = creatureId; return *this; } + FindCreatureOptions& SetStringId(std::string_view stringId) { StringId = stringId; return *this; } + + FindCreatureOptions& SetIsAlive(bool isAlive) { IsAlive = isAlive; return *this; } + FindCreatureOptions& SetIsInCombat(bool isInCombat) { IsInCombat = isInCombat; return *this; } + FindCreatureOptions& SetIsSummon(bool isSummon) { IsSummon = isSummon; return *this; } + + FindCreatureOptions& SetIgnorePhases(bool ignorePhases) { IgnorePhases = ignorePhases; return *this; } + FindCreatureOptions& SetIgnoreNotOwnedPrivateObjects(bool ignoreNotOwnedPrivateObjects) { IgnoreNotOwnedPrivateObjects = ignoreNotOwnedPrivateObjects; return *this; } + FindCreatureOptions& SetIgnorePrivateObjects(bool ignorePrivateObjects) { IgnorePrivateObjects = ignorePrivateObjects; return *this; } + + FindCreatureOptions& SetHasAura(uint32 spellId) { AuraSpellId = spellId; return *this; } + FindCreatureOptions& SetOwner(ObjectGuid ownerGuid) { OwnerGuid = ownerGuid; return *this; } + FindCreatureOptions& SetCharmer(ObjectGuid charmerGuid) { CharmerGuid = charmerGuid; return *this; } + FindCreatureOptions& SetCreator(ObjectGuid creatorGuid) { CreatorGuid = creatorGuid; return *this; } + FindCreatureOptions& SetPrivateObjectOwner(ObjectGuid privateObjectOwnerGuid) { PrivateObjectOwnerGuid = privateObjectOwnerGuid; return *this; } + + Optional CreatureId; + Optional StringId; + + Optional IsAlive; + Optional IsInCombat; + Optional IsSummon; + + bool IgnorePhases; + bool IgnoreNotOwnedPrivateObjects; + bool IgnorePrivateObjects; + + Optional AuraSpellId; + Optional OwnerGuid; + Optional CharmerGuid; + Optional CreatorGuid; + Optional PrivateObjectOwnerGuid; + + FindCreatureOptions(FindCreatureOptions const&) = delete; + FindCreatureOptions(FindCreatureOptions&&) = delete; + + FindCreatureOptions& operator=(FindCreatureOptions const&) = delete; + FindCreatureOptions& operator=(FindCreatureOptions&&) = delete; +}; + +struct FindGameObjectOptions +{ + Optional GameObjectId; + Optional StringId; + + Optional IsSummon; + Optional IsSpawned; + + bool IgnorePhases = false; + bool IgnoreNotOwnedPrivateObjects = true; + bool IgnorePrivateObjects = false; + + Optional OwnerGuid; + Optional PrivateObjectOwnerGuid; + Optional GameObjectType; +}; + class TC_GAME_API WorldObject : public Object, public WorldLocation { protected: @@ -418,15 +480,17 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation void ClearZoneScript(); ZoneScript* GetZoneScript() const { return m_zoneScript; } - TempSummon* SummonCreature(uint32 entry, Position const& pos, TempSummonType despawnType = TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime = 0s, uint32 vehId = 0, uint32 spellId = 0, bool visibleBySummonerOnly = false); - TempSummon* SummonCreature(uint32 entry, float x, float y, float z, float o = 0, TempSummonType despawnType = TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime = 0s, bool visibleBySummonerOnly = false); + TempSummon* SummonCreature(uint32 entry, Position const& pos, TempSummonType despawnType = TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime = 0s, uint32 vehId = 0, uint32 spellId = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty); + TempSummon* SummonCreature(uint32 entry, float x, float y, float z, float o = 0, TempSummonType despawnType = TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime = 0s, ObjectGuid privateObjectOwner = ObjectGuid::Empty); GameObject* SummonGameObject(uint32 entry, Position const& pos, QuaternionData const& rot, Seconds respawnTime, GOSummonType summonType = GO_SUMMON_TIMED_OR_CORPSE_DESPAWN); GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, QuaternionData const& rot, Seconds respawnTime, GOSummonType summonType = GO_SUMMON_TIMED_OR_CORPSE_DESPAWN); Creature* SummonTrigger(float x, float y, float z, float ang, Milliseconds despawnTime, CreatureAI* (*GetAI)(Creature*) = nullptr); void SummonCreatureGroup(uint8 group, std::list* list = nullptr); Creature* FindNearestCreature(uint32 entry, float range, bool alive = true) const; + Creature* FindNearestCreatureWithOptions(float range, FindCreatureOptions const& options) const; GameObject* FindNearestGameObject(uint32 entry, float range, bool spawnedOnly = true) const; + GameObject* FindNearestGameObjectWithOptions(float range, FindGameObjectOptions const& options) const; GameObject* FindNearestUnspawnedGameObject(uint32 entry, float range) const; GameObject* FindNearestGameObjectOfType(GameobjectTypes type, float range) const; Player* SelectNearestPlayer(float distance) const; @@ -483,9 +547,15 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation template void GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange = 250.0f) const; + template + void GetGameObjectListWithOptionsInGrid(Container& gameObjectContainer, float maxSearchRange, FindGameObjectOptions const& options) const; + template void GetCreatureListWithEntryInGrid(Container& creatureContainer, uint32 entry, float maxSearchRange = 250.0f) const; + template + void GetCreatureListWithOptionsInGrid(Container& creatureContainer, float maxSearchRange, FindCreatureOptions const& options) const; + template void GetPlayerListInGrid(Container& playerContainer, float maxSearchRange, bool alive = true) const; @@ -546,6 +616,12 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation // Event handler EventProcessor m_Events; + // Watcher + bool IsPrivateObject() const { return !_privateObjectOwner.IsEmpty(); } + ObjectGuid GetPrivateObjectOwner() const { return _privateObjectOwner; } + void SetPrivateObjectOwner(ObjectGuid const& owner) { _privateObjectOwner = owner; } + bool CheckPrivateObjectOwnerVisibility(WorldObject const* seer) const; + protected: std::string m_name; bool m_isActive; @@ -582,6 +658,9 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint32 m_phaseMask; // in area phase state uint16 m_notifyflags; + + ObjectGuid _privateObjectOwner; + virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool incOwnRadius = true, bool incTargetRadius = true) const; bool CanNeverSee(WorldObject const* obj) const; diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index 18fc2590554..44097221333 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -55,7 +55,7 @@ enum TypeMask TYPEMASK_DYNAMICOBJECT = 0x0040, TYPEMASK_CORPSE = 0x0080, - TYPEMASK_SEER = TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT, + TYPEMASK_SEER = TYPEMASK_UNIT | TYPEMASK_PLAYER | TYPEMASK_DYNAMICOBJECT, TYPEMASK_WORLDOBJECT = TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT | TYPEMASK_CORPSE }; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 6e71293c3c7..36272f758fd 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1325,9 +1325,7 @@ void Player::Update(uint32 p_time) m_hostileReferenceCheckTimer -= p_time; } - //we should execute delayed teleports only for alive(!) players - //because we don't want player's ghost teleported from graveyard - if (IsHasDelayedTeleport() && IsAlive()) + if (IsHasDelayedTeleport()) TeleportTo(m_teleport_dest, m_teleport_options); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e75375d2070..dbd634ea740 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -411,10 +411,10 @@ Unit::~Unit() _DeleteRemovedAuras(); - delete i_motionMaster; - delete m_charmInfo; - delete movespline; - delete _spellHistory; + delete std::exchange(i_motionMaster, nullptr); + delete std::exchange(m_charmInfo, nullptr); + delete std::exchange(movespline, nullptr); + delete std::exchange(_spellHistory, nullptr); ASSERT(!m_duringRemoveFromWorld); ASSERT(!m_attacking); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 31a1fa1d2a9..a369d0dd5bb 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -495,7 +495,9 @@ void ObjectMgr::LoadCreatureTemplates() // 62 "flags_extra," // 63 - "ScriptName" + "ScriptName," + // 64 + "StringId" " FROM creature_template ct" " LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId"); @@ -615,6 +617,7 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.SpellSchoolImmuneMask = fields[61].GetUInt32(); creatureTemplate.flags_extra = fields[62].GetUInt32(); creatureTemplate.ScriptID = GetScriptId(fields[63].GetString()); + creatureTemplate.StringId = fields[64].GetString(); } void ObjectMgr::LoadCreatureTemplateResistances() @@ -2164,8 +2167,8 @@ void ObjectMgr::LoadCreatures() QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, position_x, position_y, position_z, orientation, modelid, equipment_id, spawntimesecs, wander_distance, " // 11 12 13 14 15 16 17 18 19 20 21 "currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, poolSpawnId, creature.npcflag, creature.unit_flags, creature.dynamicflags, " - // 22 - "creature.ScriptName " + // 22 23 + "creature.ScriptName, creature.StringId " "FROM creature " "LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid " "LEFT OUTER JOIN pool_members ON pool_members.type = 0 AND creature.guid = pool_members.spawnId"); @@ -2221,6 +2224,7 @@ void ObjectMgr::LoadCreatures() data.unit_flags = fields[20].GetUInt32(); data.dynamicflags = fields[21].GetUInt32(); data.scriptId = GetScriptId(fields[22].GetString()); + data.StringId = fields[23].GetString(); data.spawnGroupData = GetDefaultSpawnGroup(); MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapId); @@ -2485,8 +2489,8 @@ void ObjectMgr::LoadGameObjects() QueryResult result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, " // 7 8 9 10 11 12 13 14 15 16 17 "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, eventEntry, poolSpawnId, " - // 18 - "ScriptName " + // 18 19 + "ScriptName, StringId " "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid " "LEFT OUTER JOIN pool_members ON pool_members.type = 1 AND gameobject.guid = pool_members.spawnId"); @@ -2590,6 +2594,7 @@ void ObjectMgr::LoadGameObjects() uint32 PoolId = fields[17].GetUInt32(); data.scriptId = GetScriptId(fields[18].GetString()); + data.StringId = fields[19].GetString(); if (data.rotation.x < -1.0f || data.rotation.x > 1.0f) { @@ -7661,8 +7666,8 @@ void ObjectMgr::LoadGameObjectTemplate() QueryResult result = WorldDatabase.Query("SELECT entry, type, displayId, name, IconName, castBarCaption, unk1, size, " // 8 9 10 11 12 13 14 15 16 17 18 19 20 "Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, " - // 21 22 23 24 25 26 27 28 29 30 31 32 33 - "Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, AIName, ScriptName " + // 21 22 23 24 25 26 27 28 29 30 31 32 33 34 + "Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, AIName, ScriptName, StringId " "FROM gameobject_template"); if (!result) @@ -7693,6 +7698,7 @@ void ObjectMgr::LoadGameObjectTemplate() got.AIName = fields[32].GetString(); got.ScriptId = GetScriptId(fields[33].GetString()); + got.StringId = fields[34].GetString(); // Checks if (!got.AIName.empty() && !sGameObjectAIRegistry->HasItem(got.AIName)) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 5448b8e93d9..a5990e8817c 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -32,6 +32,15 @@ namespace Trinity { + template + struct GridMapTypeMaskForType : std::integral_constant { }; + + template<> struct GridMapTypeMaskForType : std::integral_constant { }; + template<> struct GridMapTypeMaskForType : std::integral_constant { }; + template<> struct GridMapTypeMaskForType : std::integral_constant { }; + template<> struct GridMapTypeMaskForType : std::integral_constant { }; + template<> struct GridMapTypeMaskForType : std::integral_constant { }; + struct TC_GAME_API VisibleNotifier { Player &i_player; @@ -191,10 +200,53 @@ namespace Trinity // SEARCHERS & LIST SEARCHERS & WORKERS // WorldObject searchers & workers + enum class WorldObjectSearcherContinuation + { + Continue, + Return + }; + + template + class SearcherFirstObjectResult + { + Type& result; + + protected: + explicit SearcherFirstObjectResult(Type& ref_) : result(ref_) { } + + WorldObjectSearcherContinuation ShouldContinue() const + { + return result ? WorldObjectSearcherContinuation::Return : WorldObjectSearcherContinuation::Continue; + } + + void Insert(Type object) + { + result = object; + } + }; + + template + class SearcherLastObjectResult + { + Type& result; + + protected: + explicit SearcherLastObjectResult(Type& ref_) : result(ref_) { } + + WorldObjectSearcherContinuation ShouldContinue() const + { + return WorldObjectSearcherContinuation::Continue; + } + + void Insert(Type object) + { + result = object; + } + }; // Generic base class to insert elements into arbitrary containers using push_back template - class ContainerInserter + class SearcherContainerResult { using InserterType = void(*)(void*, Type&&); @@ -203,7 +255,7 @@ namespace Trinity protected: template - ContainerInserter(T& ref_) : ref(&ref_) + explicit SearcherContainerResult(T& ref_) : ref(&ref_) { inserter = [](void* containerRaw, Type&& object) { @@ -212,71 +264,52 @@ namespace Trinity }; } + WorldObjectSearcherContinuation ShouldContinue() const + { + return WorldObjectSearcherContinuation::Continue; + } + void Insert(Type object) { inserter(ref, std::move(object)); } }; - template - struct WorldObjectSearcher + template + struct WorldObjectSearcherBase : Result { uint32 i_mapTypeMask; uint32 i_phaseMask; - WorldObject* &i_object; - Check &i_check; - - WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + Check& i_check; - void Visit(GameObjectMapType &m); - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &m); - void Visit(DynamicObjectMapType &m); + template + WorldObjectSearcherBase(uint32 phaseMask, Container& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : Result(result), i_mapTypeMask(mapTypeMask), i_phaseMask(phaseMask), i_check(check) { } - template void Visit(GridRefManager &) { } + template + void Visit(GridRefManager&); }; template - struct WorldObjectLastSearcher + struct WorldObjectSearcher : WorldObjectSearcherBase> { - uint32 i_mapTypeMask; - uint32 i_phaseMask; - WorldObject* &i_object; - Check &i_check; - - WorldObjectLastSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } - - void Visit(GameObjectMapType &m); - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &m); - void Visit(DynamicObjectMapType &m); - - template void Visit(GridRefManager &) { } + WorldObjectSearcher(WorldObject const* searcher, WorldObject*& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : WorldObjectSearcherBase>(searcher->GetPhaseMask(), result, check, mapTypeMask) { } }; template - struct WorldObjectListSearcher : ContainerInserter + struct WorldObjectLastSearcher : WorldObjectSearcherBase> { - uint32 i_mapTypeMask; - uint32 i_phaseMask; - Check& i_check; + WorldObjectLastSearcher(WorldObject const* searcher, WorldObject*& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : WorldObjectSearcherBase>(searcher->GetPhaseMask(), result, check, mapTypeMask) { } + }; + template + struct WorldObjectListSearcher : WorldObjectSearcherBase> + { template - WorldObjectListSearcher(WorldObject const* searcher, Container& container, Check & check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : ContainerInserter(container), - i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_check(check) { } - - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &m); - void Visit(GameObjectMapType &m); - void Visit(DynamicObjectMapType &m); - - template void Visit(GridRefManager &) { } + WorldObjectListSearcher(WorldObject const* searcher, Container& container, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : WorldObjectSearcherBase>(searcher->GetPhaseMask(), container, check, mapTypeMask) { } }; template @@ -289,100 +322,55 @@ namespace Trinity WorldObjectWorker(WorldObject const* searcher, Do const& _do, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_do(_do) { } - void Visit(GameObjectMapType &m) - { - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) - return; - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - i_do(itr->GetSource()); - } - - void Visit(PlayerMapType &m) - { - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) - return; - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - i_do(itr->GetSource()); - } - void Visit(CreatureMapType &m) - { - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) - return; - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - i_do(itr->GetSource()); - } - - void Visit(CorpseMapType &m) + template + void Visit(GridRefManager& m) { - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) + if (!(i_mapTypeMask & GridMapTypeMaskForType::value)) return; - for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + for (auto itr = m.begin(); itr != m.end(); ++itr) if (itr->GetSource()->InSamePhase(i_phaseMask)) i_do(itr->GetSource()); } - - void Visit(DynamicObjectMapType &m) - { - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) - return; - for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - i_do(itr->GetSource()); - } - - template void Visit(GridRefManager &) { } }; // Gameobject searchers - template - struct GameObjectSearcher + template + struct GameObjectSearcherBase : Result { uint32 i_phaseMask; - GameObject* &i_object; Check &i_check; - GameObjectSearcher(WorldObject const* searcher, GameObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + template + GameObjectSearcherBase(uint32 phaseMask, Container& result, Check& check) + : Result(result), i_phaseMask(phaseMask), i_check(check) { } - void Visit(GameObjectMapType &m); + void Visit(GameObjectMapType& m); template void Visit(GridRefManager &) { } }; - // Last accepted by Check GO if any (Check can change requirements at each call) template - struct GameObjectLastSearcher + struct GameObjectSearcher : GameObjectSearcherBase> { - uint32 i_phaseMask; - GameObject* &i_object; - Check& i_check; - - GameObjectLastSearcher(WorldObject const* searcher, GameObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) { } + GameObjectSearcher(WorldObject const* searcher, GameObject*& result, Check& check) + : GameObjectSearcherBase>(searcher->GetPhaseMask(), result, check) { } }; + // Last accepted by Check GO if any (Check can change requirements at each call) template - struct GameObjectListSearcher : ContainerInserter + struct GameObjectLastSearcher : GameObjectSearcherBase> { - uint32 i_phaseMask; - Check& i_check; + GameObjectLastSearcher(WorldObject const* searcher, GameObject*& result, Check& check) + : GameObjectSearcherBase>(searcher->GetPhaseMask(), result, check) { } + }; + template + struct GameObjectListSearcher : GameObjectSearcherBase> + { template - GameObjectListSearcher(WorldObject const* searcher, Container& container, Check & check) - : ContainerInserter(container), - i_phaseMask(searcher->GetPhaseMask()), i_check(check) { } - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) { } + GameObjectListSearcher(WorldObject const* searcher, Container& container, Check& check) + : GameObjectSearcherBase>(searcher->GetPhaseMask(), container, check) { } }; template @@ -407,105 +395,88 @@ namespace Trinity // Unit searchers - // First accepted by Check Unit if any - template - struct UnitSearcher + template + struct UnitSearcherBase : Result { uint32 i_phaseMask; - Unit* &i_object; - Check & i_check; + Check& i_check; - UnitSearcher(WorldObject const* searcher, Unit* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + template + UnitSearcherBase(uint32 phaseMask, Container& result, Check& check) + : Result(result), i_phaseMask(phaseMask), i_check(check) { } - void Visit(CreatureMapType &m); - void Visit(PlayerMapType &m); + void Visit(CreatureMapType& m) { VisitImpl(m); } + void Visit(PlayerMapType& m) { VisitImpl(m); } - template void Visit(GridRefManager &) { } + template void Visit(GridRefManager&) { } + + private: + template void VisitImpl(GridRefManager& m); }; - // Last accepted by Check Unit if any (Check can change requirements at each call) + // First accepted by Check Unit if any template - struct UnitLastSearcher + struct UnitSearcher : UnitSearcherBase> { - uint32 i_phaseMask; - Unit* &i_object; - Check & i_check; - - UnitLastSearcher(WorldObject const* searcher, Unit* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } - - void Visit(CreatureMapType &m); - void Visit(PlayerMapType &m); + UnitSearcher(WorldObject const* searcher, Unit*& result, Check& check) + : UnitSearcherBase>(searcher->GetPhaseMask(), result, check) { } + }; - template void Visit(GridRefManager &) { } + // Last accepted by Check Unit if any (Check can change requirements at each call) + template + struct UnitLastSearcher : UnitSearcherBase> + { + UnitLastSearcher(WorldObject const* searcher, Unit*& result, Check& check) + : UnitSearcherBase>(searcher->GetPhaseMask(), result, check) { } }; // All accepted by Check units if any template - struct UnitListSearcher : ContainerInserter + struct UnitListSearcher : UnitSearcherBase> { - uint32 i_phaseMask; - Check& i_check; - template UnitListSearcher(WorldObject const* searcher, Container& container, Check& check) - : ContainerInserter(container), - i_phaseMask(searcher->GetPhaseMask()), i_check(check) { } - - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) { } + : UnitSearcherBase>(searcher->GetPhaseMask(), container, check) { } }; // Creature searchers - template - struct CreatureSearcher + template + struct CreatureSearcherBase : Result { uint32 i_phaseMask; - Creature* &i_object; - Check & i_check; + Check& i_check; - CreatureSearcher(WorldObject const* searcher, Creature* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + template + CreatureSearcherBase(uint32 phaseMask, Container& result, Check& check) + : Result(result), i_phaseMask(phaseMask), i_check(check) { } - void Visit(CreatureMapType &m); + void Visit(CreatureMapType& m); template void Visit(GridRefManager &) { } }; - // Last accepted by Check Creature if any (Check can change requirements at each call) template - struct CreatureLastSearcher + struct CreatureSearcher : CreatureSearcherBase> { - uint32 i_phaseMask; - Creature* &i_object; - Check & i_check; - - CreatureLastSearcher(WorldObject const* searcher, Creature* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) { } + CreatureSearcher(WorldObject const* searcher, Creature*& result, Check& check) + : CreatureSearcherBase>(searcher->GetPhaseMask(), result, check) { } }; + // Last accepted by Check Creature if any (Check can change requirements at each call) template - struct CreatureListSearcher : ContainerInserter + struct CreatureLastSearcher : CreatureSearcherBase> { - uint32 i_phaseMask; - Check& i_check; + CreatureLastSearcher(WorldObject const* searcher, Creature*& result, Check& check) + : CreatureSearcherBase>(searcher->GetPhaseMask(), result, check) { } + }; + template + struct CreatureListSearcher : CreatureSearcherBase> + { template CreatureListSearcher(WorldObject const* searcher, Container& container, Check & check) - : ContainerInserter(container), - i_phaseMask(searcher->GetPhaseMask()), i_check(check) { } - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) { } + : CreatureSearcherBase>(searcher->GetPhaseMask(), container, check) { } }; template @@ -529,56 +500,45 @@ namespace Trinity // Player searchers - template - struct PlayerSearcher + template + struct PlayerSearcherBase : Result { uint32 i_phaseMask; - Player* &i_object; - Check & i_check; + Check& i_check; - PlayerSearcher(WorldObject const* searcher, Player* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + template + PlayerSearcherBase(uint32 phaseMask, Container& result, Check& check) + : Result(result), i_phaseMask(phaseMask), i_check(check) { } - void Visit(PlayerMapType &m); + void Visit(PlayerMapType& m); template void Visit(GridRefManager &) { } }; template - struct PlayerListSearcher : ContainerInserter + struct PlayerSearcher : PlayerSearcherBase> { - uint32 i_phaseMask; - Check& i_check; - - template - PlayerListSearcher(WorldObject const* searcher, Container& container, Check & check) - : ContainerInserter(container), - i_phaseMask(searcher->GetPhaseMask()), i_check(check) { } - - template - PlayerListSearcher(uint32 phaseMask, Container& container, Check & check) - : ContainerInserter(container), - i_phaseMask(phaseMask), i_check(check) { } - - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) { } + PlayerSearcher(WorldObject const* searcher, Player*& result, Check& check) + : PlayerSearcherBase>(searcher->GetPhaseMask(), result, check) { } }; template - struct PlayerLastSearcher + struct PlayerLastSearcher : PlayerSearcherBase> { - uint32 i_phaseMask; - Player* &i_object; - Check& i_check; - - PlayerLastSearcher(WorldObject const* searcher, Player*& result, Check& check) : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) - { - } + PlayerLastSearcher(WorldObject const* searcher, Player*& result, Check& check) + : PlayerSearcherBase>(searcher->GetPhaseMask(), result, check) { } + }; - void Visit(PlayerMapType& m); + template + struct PlayerListSearcher : PlayerSearcherBase> + { + template + PlayerListSearcher(WorldObject const* searcher, Container& container, Check& check) + : PlayerSearcherBase>(searcher->GetPhaseMask(), container, check) { } - template void Visit(GridRefManager &) { } + template + PlayerListSearcher(uint32 phaseMask, Container& container, Check& check) + : PlayerSearcherBase>(phaseMask, container, check) { } }; template @@ -622,6 +582,44 @@ namespace Trinity // CHECKS && DO classes + // CHECK modifiers + class InRangeCheckCustomizer + { + public: + explicit InRangeCheckCustomizer(WorldObject const& obj, float range) : i_obj(obj), i_range(range) { } + + bool Test(WorldObject const* o) const + { + return i_obj.IsWithinDist(o, i_range); + } + + void Update(WorldObject const* /*o*/) { } + + private: + WorldObject const& i_obj; + float i_range; + }; + + class NearestCheckCustomizer + { + public: + explicit NearestCheckCustomizer(WorldObject const& obj, float range) : i_obj(obj), i_range(range) { } + + bool Test(WorldObject const* o) const + { + return i_obj.IsWithinDistInMap(o, i_range); + } + + void Update(WorldObject const* o) + { + i_range = i_obj.GetDistance(o); + } + + private: + WorldObject const& i_obj; + float i_range; + }; + // WorldObject check classes class TC_GAME_API AnyDeadUnitObjectInRangeCheck @@ -1375,7 +1373,12 @@ namespace Trinity bool operator()(Creature* u) { - if (u->getDeathState() != DEAD && u->GetEntry() == i_entry && u->IsAlive() == i_alive && u->GetGUID() != i_obj.GetGUID() && i_obj.IsWithinDistInMap(u, i_range)) + if (u->getDeathState() != DEAD + && u->GetEntry() == i_entry + && u->IsAlive() == i_alive + && u->GetGUID() != i_obj.GetGUID() + && i_obj.IsWithinDistInMap(u, i_range) + && u->CheckPrivateObjectOwnerVisibility(&i_obj)) { i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check return true; @@ -1393,6 +1396,114 @@ namespace Trinity NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&) = delete; }; + template + class CreatureWithOptionsInObjectRangeCheck + { + public: + CreatureWithOptionsInObjectRangeCheck(WorldObject const& obj, Customizer& customizer, FindCreatureOptions const& args) + : i_obj(obj), i_args(args), i_customizer(customizer) { } + + bool operator()(Creature const* u) const + { + if (u->getDeathState() == DEAD) // Despawned + return false; + + if (u->GetGUID() == i_obj.GetGUID()) + return false; + + if (!i_customizer.Test(u)) + return false; + + if (i_args.CreatureId && u->GetEntry() != i_args.CreatureId) + return false; + + if (i_args.StringId && !u->HasStringId(*i_args.StringId)) + return false; + + if (i_args.IsAlive.has_value() && u->IsAlive() != i_args.IsAlive) + return false; + + if (i_args.IsSummon.has_value() && u->IsSummon() != i_args.IsSummon) + return false; + + if (i_args.IsInCombat.has_value() && u->IsInCombat() != i_args.IsInCombat) + return false; + + if ((i_args.OwnerGuid && u->GetOwnerGUID() != i_args.OwnerGuid) + || (i_args.CharmerGuid && u->GetCharmerGUID() != i_args.CharmerGuid) + || (i_args.CreatorGuid && u->GetCreatorGUID() != i_args.CreatorGuid) + || (i_args.PrivateObjectOwnerGuid && u->GetPrivateObjectOwner() != i_args.PrivateObjectOwnerGuid)) + return false; + + if (i_args.IgnorePrivateObjects && u->IsPrivateObject()) + return false; + + if (i_args.IgnoreNotOwnedPrivateObjects && !u->CheckPrivateObjectOwnerVisibility(&i_obj)) + return false; + + if (i_args.AuraSpellId && !u->HasAura(*i_args.AuraSpellId)) + return false; + + i_customizer.Update(u); + return true; + } + + private: + WorldObject const& i_obj; + FindCreatureOptions const& i_args; + Customizer& i_customizer; + }; + + template + class GameObjectWithOptionsInObjectRangeCheck + { + public: + GameObjectWithOptionsInObjectRangeCheck(WorldObject const& obj, Customizer& customizer, FindGameObjectOptions const& args) + : i_obj(obj), i_args(args), i_customizer(customizer) { } + + bool operator()(GameObject const* go) const + { + if (i_args.IsSpawned.has_value() && i_args.IsSpawned != go->isSpawned()) // Despawned + return false; + + if (go->GetGUID() == i_obj.GetGUID()) + return false; + + if (!i_customizer.Test(go)) + return false; + + if (i_args.GameObjectId && go->GetEntry() != i_args.GameObjectId) + return false; + + if (i_args.StringId && !go->HasStringId(*i_args.StringId)) + return false; + + if (i_args.IsSummon.has_value() && (go->GetSpawnId() == 0) != i_args.IsSummon) + return false; + + if ((i_args.OwnerGuid && go->GetOwnerGUID() != i_args.OwnerGuid) + || (i_args.PrivateObjectOwnerGuid && go->GetPrivateObjectOwner() != i_args.PrivateObjectOwnerGuid)) + return false; + + if (i_args.IgnorePrivateObjects && go->IsPrivateObject()) + return false; + + if (i_args.IgnoreNotOwnedPrivateObjects && !go->CheckPrivateObjectOwnerVisibility(&i_obj)) + return false; + + if (i_args.GameObjectType && go->GetGoType() != i_args.GameObjectType) + return false; + + i_customizer.Update(go); + return true; + } + + private: + WorldObject const& i_obj; + FindGameObjectOptions const& i_args; + Customizer& i_customizer; + }; + class AnyPlayerInObjectRangeCheck { public: diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index 5c2d958ed2c..2a852b6c046 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -41,469 +41,118 @@ inline void Trinity::VisibleNotifier::Visit(GridRefManager &m) // WorldObject searchers & workers -template -void Trinity::WorldObjectSearcher::Visit(GameObjectMapType &m) +template +template +void Trinity::WorldObjectSearcherBase::Visit(GridRefManager& m) { - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) + if (!(i_mapTypeMask & GridMapTypeMaskForType::value)) return; - // already found - if (i_object) + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) return; - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + for (GridReference const& ref : m) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) + if (i_check(ref.GetSource())) { - i_object = itr->GetSource(); - return; - } - } -} - -template -void Trinity::WorldObjectSearcher::Visit(PlayerMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) - return; - - // already found - if (i_object) - return; - - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; + this->Insert(ref.GetSource()); - if (i_check(itr->GetSource())) - { - i_object = itr->GetSource(); - return; + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) + return; } } } -template -void Trinity::WorldObjectSearcher::Visit(CreatureMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) - return; - - // already found - if (i_object) - return; - - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - { - i_object = itr->GetSource(); - return; - } - } -} - -template -void Trinity::WorldObjectSearcher::Visit(CorpseMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) - return; - - // already found - if (i_object) - return; - - for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - { - i_object = itr->GetSource(); - return; - } - } -} - -template -void Trinity::WorldObjectSearcher::Visit(DynamicObjectMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) - return; - - // already found - if (i_object) - return; - - for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - { - i_object = itr->GetSource(); - return; - } - } -} - -template -void Trinity::WorldObjectLastSearcher::Visit(GameObjectMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) - return; - - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); - } -} - -template -void Trinity::WorldObjectLastSearcher::Visit(PlayerMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) - return; - - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); - } -} - -template -void Trinity::WorldObjectLastSearcher::Visit(CreatureMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) - return; - - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); - } -} - -template -void Trinity::WorldObjectLastSearcher::Visit(CorpseMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) - return; - - for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); - } -} - -template -void Trinity::WorldObjectLastSearcher::Visit(DynamicObjectMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) - return; - - for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); - } -} - -template -void Trinity::WorldObjectListSearcher::Visit(PlayerMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) - return; - - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(CreatureMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) - return; - - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(CorpseMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) - return; - - for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(GameObjectMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) - return; - - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(DynamicObjectMapType &m) -{ - if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) - return; - - for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - // Gameobject searchers -template -void Trinity::GameObjectSearcher::Visit(GameObjectMapType &m) +template +void Trinity::GameObjectSearcherBase::Visit(GameObjectMapType& m) { - // already found - if (i_object) + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) return; - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + for (GridReference const& ref : m) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!ref.GetSource()->InSamePhase(i_phaseMask)) continue; - if (i_check(itr->GetSource())) + if (i_check(ref.GetSource())) { - i_object = itr->GetSource(); - return; - } - } -} + this->Insert(ref.GetSource()); -template -void Trinity::GameObjectLastSearcher::Visit(GameObjectMapType &m) -{ - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) + return; + } } } -template -void Trinity::GameObjectListSearcher::Visit(GameObjectMapType &m) -{ - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - // Unit searchers -template -void Trinity::UnitSearcher::Visit(CreatureMapType &m) +template +template +void Trinity::UnitSearcherBase::VisitImpl(GridRefManager& m) { - // already found - if (i_object) + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) return; - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + for (GridReference const& ref : m) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!ref.GetSource()->InSamePhase(i_phaseMask)) continue; - if (i_check(itr->GetSource())) + if (i_check(ref.GetSource())) { - i_object = itr->GetSource(); - return; - } - } -} - -template -void Trinity::UnitSearcher::Visit(PlayerMapType &m) -{ - // already found - if (i_object) - return; - - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; + this->Insert(ref.GetSource()); - if (i_check(itr->GetSource())) - { - i_object = itr->GetSource(); - return; + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) + return; } } } -template -void Trinity::UnitLastSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); - } -} - -template -void Trinity::UnitLastSearcher::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); - } -} - -template -void Trinity::UnitListSearcher::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - -template -void Trinity::UnitListSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - // Creature searchers -template -void Trinity::CreatureSearcher::Visit(CreatureMapType &m) +template +void Trinity::CreatureSearcherBase::Visit(CreatureMapType& m) { - // already found - if (i_object) + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) return; - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + for (GridReference const& ref : m) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!ref.GetSource()->InSamePhase(i_phaseMask)) continue; - if (i_check(itr->GetSource())) + if (i_check(ref.GetSource())) { - i_object = itr->GetSource(); - return; - } - } -} - -template -void Trinity::CreatureLastSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; + this->Insert(ref.GetSource()); - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) + return; + } } } -template -void Trinity::CreatureListSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} +// Player searchers -template -void Trinity::PlayerListSearcher::Visit(PlayerMapType &m) +template +void Trinity::PlayerSearcherBase::Visit(PlayerMapType& m) { - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->GetSource())) - Insert(itr->GetSource()); -} - -template -void Trinity::PlayerSearcher::Visit(PlayerMapType &m) -{ - // already found - if (i_object) + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) return; - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + for (GridReference const& ref : m) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!ref.GetSource()->InSamePhase(i_phaseMask)) continue; - if (i_check(itr->GetSource())) + if (i_check(ref.GetSource())) { - i_object = itr->GetSource(); - return; - } - } -} + this->Insert(ref.GetSource()); -template -void Trinity::PlayerLastSearcher::Visit(PlayerMapType& m) -{ - for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr) - { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->GetSource())) - i_object = itr->GetSource(); + if (this->ShouldContinue() == WorldObjectSearcherContinuation::Return) + return; + } } } diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 8d9ce0217ae..1b47558c802 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -595,12 +595,12 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) stmt->setUInt32(2, realm.Id.Realm); trans->Append(stmt); - LoginDatabase.CommitTransaction(trans); - - AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(characterTransaction)).AfterComplete([this, newChar = std::move(newChar)](bool success) + AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(characterTransaction)).AfterComplete([this, newChar = std::move(newChar), trans](bool success) { if (success) { + LoginDatabase.CommitTransaction(trans); + TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Create Character: {} {}", GetAccountId(), GetRemoteAddress(), newChar->GetName(), newChar->GetGUID().ToString()); sScriptMgr->OnPlayerCreate(newChar.get()); sCharacterCache->AddCharacterCacheEntry(newChar->GetGUID(), GetAccountId(), newChar->GetName(), newChar->GetNativeGender(), newChar->GetRace(), newChar->GetClass(), newChar->GetLevel()); diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 50f5cefe9eb..c6e0d7e2fc8 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -649,6 +649,9 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) case EMOTE_STATE_KNEEL: case EMOTE_ONESHOT_NONE: break; + case EMOTE_STATE_DANCE: + GetPlayer()->SetEmoteState(emote); + break; default: // Only allow text-emotes for "dead" entities (feign death included) if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index ba07bc7576e..f15283bca9d 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -304,6 +304,10 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket) if (!mover->movespline->Finalized()) return; + // stop some emotes at player move + if (plrMover && (plrMover->GetEmoteState() != 0)) + plrMover->SetEmoteState(EMOTE_ONESHOT_NONE); + /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) { diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 84783d95c0c..af77c925858 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -505,7 +505,7 @@ class TC_GAME_API Map : public GridRefManager void UpdateIteratorBack(Player* player); - TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = nullptr, uint32 duration = 0, WorldObject* summoner = nullptr, uint32 spellId = 0, uint32 vehId = 0, bool visibleOnlyBySummoner = false); + TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = nullptr, uint32 duration = 0, WorldObject* summoner = nullptr, uint32 spellId = 0, uint32 vehId = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty); void SummonCreatureGroup(uint8 group, std::list* list = nullptr); Player* GetPlayer(ObjectGuid const& guid); Corpse* GetCorpse(ObjectGuid const& guid); diff --git a/src/server/game/Maps/SpawnData.h b/src/server/game/Maps/SpawnData.h index 863fa13f4bc..d12b814f91f 100644 --- a/src/server/game/Maps/SpawnData.h +++ b/src/server/game/Maps/SpawnData.h @@ -99,6 +99,7 @@ struct SpawnData : public SpawnMetadata int32 spawntimesecs = 0; uint8 spawnMask = 0; uint32 scriptId = 0; + std::string StringId; protected: SpawnData(SpawnObjectType t) : SpawnMetadata(t) {} diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 138991a5115..5ad1cef8d55 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1153,7 +1153,7 @@ enum TrinityStrings LANG_NPCINFO_NPC_FLAGS = 5086, // master branch ONLY LANG_NPCINFO_PHASE_IDS = 5087, // master branch ONLY LANG_SCENARIO = 5088, // master branch ONLY - LANG_OBJECTINFO_STRINGIDS = 5089, // master branch ONLY + LANG_OBJECTINFO_STRINGIDS = 5089, // Room for more Trinity strings 5090-6603 diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e4a923f51f3..c5fe2d9dfd2 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1891,9 +1891,11 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objec uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList); if (!containerTypeMask) return nullptr; + Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList); Trinity::WorldObjectLastSearcher searcher(m_caster, target, check, containerTypeMask); - SearchTargets > (searcher, containerTypeMask, m_caster, m_caster, range); + searcher.i_phaseMask = PHASEMASK_ANYWHERE; + SearchTargets>(searcher, containerTypeMask, m_caster, m_caster, range); return target; } @@ -1906,7 +1908,8 @@ void Spell::SearchAreaTargets(std::list& targets, float range, Pos float extraSearchRadius = range > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f; Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList); Trinity::WorldObjectListSearcher searcher(m_caster, targets, check, containerTypeMask); - SearchTargets > (searcher, containerTypeMask, m_caster, position, range + extraSearchRadius); + searcher.i_phaseMask = PHASEMASK_ANYWHERE; + SearchTargets>(searcher, containerTypeMask, m_caster, position, range + extraSearchRadius); } void Spell::SearchChainTargets(std::list& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer* condList, bool isChainHeal) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 423883689d7..0071823ed6e 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2038,7 +2038,9 @@ void Spell::EffectSummonType() if (m_originalCaster) caster = m_originalCaster; - bool personalSpawn = (properties->Flags & SUMMON_PROP_FLAG_PERSONAL_SPAWN) != 0; + ObjectGuid privateObjectOwner; + if (properties->Flags & SUMMON_PROP_FLAG_PERSONAL_SPAWN) + privateObjectOwner = m_originalCaster->IsPrivateObject() ? m_originalCaster->GetPrivateObjectOwner() : m_originalCaster->GetGUID(); int32 duration = m_spellInfo->GetDuration(); if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); @@ -2114,7 +2116,7 @@ void Spell::EffectSummonType() if (!unitCaster) return; - summon = unitCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, unitCaster, m_spellInfo->Id, 0, personalSpawn); + summon = unitCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, unitCaster, m_spellInfo->Id, 0, privateObjectOwner); if (!summon || !summon->IsTotem()) return; @@ -2134,7 +2136,7 @@ void Spell::EffectSummonType() if (!unitCaster) return; - summon = unitCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, unitCaster, m_spellInfo->Id, 0, personalSpawn); + summon = unitCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, unitCaster, m_spellInfo->Id, 0, privateObjectOwner); if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION)) return; @@ -2158,7 +2160,7 @@ void Spell::EffectSummonType() // randomize position for multiple summons pos = caster->GetRandomPoint(*destTarget, radius); - summon = caster->SummonCreature(entry, pos, summonType, Milliseconds(duration), 0, m_spellInfo->Id, personalSpawn); + summon = caster->SummonCreature(entry, pos, summonType, Milliseconds(duration), 0, m_spellInfo->Id, privateObjectOwner); if (!summon) continue; @@ -2183,7 +2185,7 @@ void Spell::EffectSummonType() if (!unitCaster) return; - summon = unitCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, unitCaster, m_spellInfo->Id, 0, personalSpawn); + summon = unitCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, unitCaster, m_spellInfo->Id, 0, privateObjectOwner); break; } case SUMMON_CATEGORY_VEHICLE: diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 9e8529f1cb8..15150eea1c5 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -507,6 +507,8 @@ class npc_commandscript : public CommandScript handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); handler->PSendSysMessage(LANG_OBJECTINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str()); + handler->PSendSysMessage(LANG_OBJECTINFO_STRINGIDS, STRING_VIEW_FMT_ARG(target->GetStringId(StringIdType::Template)), + STRING_VIEW_FMT_ARG(target->GetStringId(StringIdType::Spawn)), STRING_VIEW_FMT_ARG(target->GetStringId(StringIdType::Script))); handler->PSendSysMessage(LANG_NPCINFO_REACTSTATE, DescribeReactState(target->GetReactState())); if (CreatureAI const* ai = target->AI()) handler->PSendSysMessage(LANG_OBJECTINFO_AITYPE, Trinity::GetTypeName(*ai).c_str()); diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 2ae3043b79c..e255a05f42f 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -2766,6 +2766,13 @@ enum CreatureEliteType CREATURE_ELITE_TRIVIAL = 5 // found in 2.2.3 for 2 mobs }; +enum class StringIdType : int32 +{ + Template = 0, + Spawn = 1, + Script = 2 +}; + // values based at Holidays.dbc enum HolidayIds {