From 2f9ced6ddc2bbc54224a8e9edbad050fc4da4800 Mon Sep 17 00:00:00 2001 From: Ovahlord <18347559+Ovahlord@users.noreply.github.com> Date: Mon, 18 Aug 2025 07:30:11 +0200 Subject: [PATCH] Core/Creatures: moved the initialization of CreatorGUIDs to new summon handling --- .../game/Entities/Creature/Creature.cpp | 46 ++++++++++++++++++- src/server/game/Entities/Creature/Creature.h | 3 ++ .../Creature/SummonInfo/SummonInfo.cpp | 1 + .../Entities/Creature/TemporarySummon.cpp | 3 -- src/server/game/Entities/Unit/Unit.cpp | 44 +++++------------- src/server/game/Entities/Unit/Unit.h | 13 ++++-- src/server/scripts/Commands/cs_pet.cpp | 2 +- src/server/scripts/Spells/spell_quest.cpp | 2 +- 8 files changed, 72 insertions(+), 42 deletions(-) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 0ab78573e5..4f03c5efa3 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -53,6 +53,7 @@ #include "SpellMgr.h" #include "SummonInfo.h" #include "TemporarySummon.h" +#include "TotemPackets.h" #include "Transport.h" #include "Util.h" #include "Vehicle.h" @@ -317,11 +318,15 @@ void Creature::AddToWorld() if (IsVehicle()) GetVehicleKit()->Install(); - // If the creature has been summoned, register it for the summoner if (SummonInfo* summonInfo = GetSummonInfo()) + { + // If the creature has been summoned, register it for the summoner if (Unit* summoner = summonInfo->GetUnitSummoner()) summoner->RegisterSummon(summonInfo); + HandlePostSummonActions(); + } + if (GetZoneScript()) GetZoneScript()->OnCreatureCreate(this); } @@ -2808,6 +2813,45 @@ bool Creature::IsSummon() const return _summonInfo != nullptr; } +void Creature::HandlePostSummonActions() +{ + SummonInfo* summonInfo = ASSERT_NOTNULL(GetSummonInfo()); + + if (Unit* summoner = summonInfo->GetUnitSummoner()) + { + SummonPropertiesSlot slot = summonInfo->GetSummonSlot(); + + // Controlled summons always set their creator guid, which is being used to display summoner names in their title + if (summonInfo->IsControlledBySummoner()) + SetCreatorGUID(summoner->GetGUID()); + + // Totem slot summons always send the TotemCreated packet. Some non-Shaman classes use this + // to display summon icons that can be canceled (Consecration, DK ghouls, Wild Mushrooms) + switch (slot) + { + case SummonPropertiesSlot::Totem1: + case SummonPropertiesSlot::Totem2: + case SummonPropertiesSlot::Totem3: + case SummonPropertiesSlot::Totem4: + { + if (Player* playerSummoner = Object::ToPlayer(summoner)) + { + WorldPackets::Totem::TotemCreated totemCreated; + totemCreated.Totem = GetGUID(); + totemCreated.SpellID = GetUInt32Value(UNIT_CREATED_BY_SPELL); + totemCreated.Duration = summonInfo->GetRemainingDuration().value_or(0ms).count(); + totemCreated.Slot = AsUnderlyingType(summonInfo->GetSummonSlot()) - 1; + + playerSummoner->SendDirectMessage(totemCreated.Write()); + } + break; + } + default: + break; + } + } +} + void Creature::AllLootRemovedFromCorpse() { if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient()) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 527bbcb3e1..89fd0a0f9c 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -430,6 +430,9 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma bool IsSummon() const override; + // Handles all summon relation actions, such as setting guid values, casting passives and initializing the control status + void HandlePostSummonActions(); + protected: bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0); bool InitEntry(uint32 entry, CreatureData const* data = nullptr); diff --git a/src/server/game/Entities/Creature/SummonInfo/SummonInfo.cpp b/src/server/game/Entities/Creature/SummonInfo/SummonInfo.cpp index 2dea277d29..d45f2177a9 100644 --- a/src/server/game/Entities/Creature/SummonInfo/SummonInfo.cpp +++ b/src/server/game/Entities/Creature/SummonInfo/SummonInfo.cpp @@ -154,6 +154,7 @@ void SummonInfo::SetUseSummonerFaction(bool set) else _flags.RemoveFlag(SummonPropertiesFlags::UseSummonerFaction); } + bool SummonInfo::IsControlledBySummoner() const { return _control > SummonPropertiesControl::None; diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index d0022d51fc..dc28e4f57d 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -189,9 +189,6 @@ void TempSummon::InitStats(uint32 duration) if (m_Properties->Control != SUMMON_CATEGORY_WILD) { - // Creator guid is always set for allied summons - SetCreatorGUID(owner->GetGUID()); - // Summons inherit their player summoner's guild data if (owner && (owner->IsPlayer() || owner->IsTotem())) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 00c0100d0a..ff48192a12 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -82,7 +82,6 @@ #include "SummonInfo.h" #include "TemporarySummon.h" #include "Totem.h" -#include "TotemPackets.h" #include "Transport.h" #include "UnitAI.h" #include "UpdateFieldFlags.h" @@ -5727,6 +5726,16 @@ void Unit::SetOwnerGUID(ObjectGuid owner) RemoveFieldNotifyFlag(UF_FLAG_OWNER); } +Unit* Unit::GetCreator() const +{ + return ObjectAccessor::GetUnit(*this, GetCreatorGUID()); +} + +Creature* Unit::GetCritter() const +{ + return ObjectAccessor::GetCreature(*this, GetCritterGUID()); +} + Player* Unit::GetControllingPlayer() const { if (ObjectGuid guid = GetCharmerOrOwnerGUID()) @@ -8840,44 +8849,13 @@ void Unit::RegisterSummon(SummonInfo* summon) return; } - // Select any available totem slot if empty, otherwise they just replace the oldest summon of the same entry - if (slot == SummonPropertiesSlot::AnyAvailableTotem) - { - // @Todo - slot = SummonPropertiesSlot::Totem1; - } - uint8 targetSlot = AsUnderlyingType(slot); - // Another is occupying the slot. Unsummon that summon first + // Another summon is occupying the slot. Unsummon that one first if (SummonInfo* activeSummon = _slottedSummons[targetSlot]) activeSummon->GetSummonedCreature()->DespawnOrUnsummon(); _slottedSummons[targetSlot] = summon; - - switch (slot) - { - case SummonPropertiesSlot::Totem1: - case SummonPropertiesSlot::Totem2: - case SummonPropertiesSlot::Totem3: - case SummonPropertiesSlot::Totem4: - { - Creature const* summonedCreature = summon->GetSummonedCreature(); - if (Player* playerSummoner = Object::ToPlayer(summon->GetUnitSummoner())) - { - WorldPackets::Totem::TotemCreated totemCreated; - totemCreated.Totem = summonedCreature->GetGUID(); - totemCreated.SpellID = summonedCreature->GetUInt32Value(UNIT_CREATED_BY_SPELL); - totemCreated.Duration = summon->GetRemainingDuration().value_or(0ms).count(); - totemCreated.Slot = AsUnderlyingType(summon->GetSummonSlot()) - 1; - - playerSummoner->SendDirectMessage(totemCreated.Write()); - } - break; - } - default: - break; - } } void Unit::UnregisterSummon(SummonInfo* summon) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index b37c6c571e..8d008a8daf 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1078,14 +1078,21 @@ class TC_GAME_API Unit : public WorldObject ObjectGuid GetOwnerGUID() const override { return GetGuidValue(UNIT_FIELD_SUMMONEDBY); } void SetOwnerGUID(ObjectGuid owner); + ObjectGuid GetCreatorGUID() const { return GetGuidValue(UNIT_FIELD_CREATEDBY); } void SetCreatorGUID(ObjectGuid creator) { SetGuidValue(UNIT_FIELD_CREATEDBY, creator); } + Unit* GetCreator() const; + ObjectGuid GetMinionGUID() const { return GetGuidValue(UNIT_FIELD_SUMMON); } void SetMinionGUID(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_SUMMON, guid); } - void SetPetGUID(ObjectGuid guid) { m_SummonSlot[SUMMON_SLOT_PET] = guid; } + ObjectGuid GetPetGUID() const { return m_SummonSlot[SUMMON_SLOT_PET]; } - void SetCritterGUID(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CRITTER, guid); } + void SetPetGUID(ObjectGuid guid) { m_SummonSlot[SUMMON_SLOT_PET] = guid; } + ObjectGuid GetCritterGUID() const { return GetGuidValue(UNIT_FIELD_CRITTER); } + void SetCritterGUID(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CRITTER, guid); } + Creature* GetCritter() const; + ObjectGuid GetOwnerOrCreatorGUID() const { return GetOwnerGUID() ? GetOwnerGUID() : GetCreatorGUID(); } ObjectGuid GetCharmerGUID() const { return GetGuidValue(UNIT_FIELD_CHARMEDBY); } @@ -1324,7 +1331,7 @@ class TC_GAME_API Unit : public WorldObject std::array m_SummonSlot; std::array m_ObjectSlot; - // Registers the SummonInfo API of a summoned creature to allow safely accessing it + // Registers the SummonInfo API of a summoned creature to allow to safely access it void RegisterSummon(SummonInfo* summon); // Unregisters the SummonInfo API of a summoned creature so it can no longer be accessed void UnregisterSummon(SummonInfo* summon); diff --git a/src/server/scripts/Commands/cs_pet.cpp b/src/server/scripts/Commands/cs_pet.cpp index 11f28b4400..959819a36a 100644 --- a/src/server/scripts/Commands/cs_pet.cpp +++ b/src/server/scripts/Commands/cs_pet.cpp @@ -103,7 +103,7 @@ public: creatureTarget->DespawnOrUnsummon(); creatureTarget->SetHealth(0); // just for nice GM-mode view - pet->SetGuidValue(UNIT_FIELD_CREATEDBY, player->GetGUID()); + pet->SetCreatorGUID(player->GetGUID()); pet->SetFaction(player->GetFaction()); if (!pet->InitStatsForLevel(creatureTarget->getLevel())) diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 9e14c942b8..e96001d3a2 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -2476,7 +2476,7 @@ public: if (Creature* injuredStormwindInfantry = caster->FindNearestCreature(NPC_INJURED_STORMWIND_INFANTRY, 5.0f, true)) { injuredStormwindInfantry->SetCreatorGUID(caster->GetGUID()); - injuredStormwindInfantry->CastSpell(injuredStormwindInfantry, SPELL_RENEWED_LIFE, true); + injuredStormwindInfantry->CastSpell(injuredStormwindInfantry, SPELL_RENEWED_LIFE); } }