From 2ded315eaa7b6c60e14b07e0f741c484cb6c3845 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 7 Dec 2021 13:53:35 -0500 Subject: [PATCH] Core/Object: Range check vol. 2 Port From (https://github.com/TrinityCore/TrinityCore/commit/a13a765610d964a3aa1bab1b41331c05e24a1f78) --- Source/Framework/Constants/CliDBConst.cs | 3 +- Source/Game/Entities/GameObject/GameObject.cs | 91 ++++++++----------- Source/Game/Entities/Player/Player.Items.cs | 2 +- Source/Game/Entities/Player/Player.cs | 2 +- Source/Game/Handlers/LootHandler.cs | 6 +- Source/Game/Handlers/SpellHandler.cs | 34 ++++++- Source/Game/Spells/Spell.cs | 5 + 7 files changed, 78 insertions(+), 65 deletions(-) diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 300c7a2ee..010b635ec 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -1505,7 +1505,8 @@ namespace Framework.Constants { None = 0, Item = 1, - Skill = 2 + Skill = 2, + Spell = 3 } public enum LockType diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index dc95e55a1..53d375060 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -2258,7 +2258,7 @@ namespace Game.Entities return localRotation; } - public bool IsAtInteractDistance(Player player, SpellInfo spell) + public bool IsAtInteractDistance(Player player, SpellInfo spell = null) { if (spell != null || (spell = GetSpellForLock(player)) != null) { @@ -2267,52 +2267,11 @@ namespace Game.Entities if (GetGoType() == GameObjectTypes.SpellFocus) return maxRange * maxRange >= GetExactDistSq(player); - var displayInfo = CliDB.GameObjectDisplayInfoStorage.LookupByKey(GetGoInfo().displayId); - if (displayInfo != null) + if (CliDB.GameObjectDisplayInfoStorage.ContainsKey(GetGoInfo().displayId)) return IsAtInteractDistance(player, maxRange); } - float distance; - switch (GetGoType()) - { - case GameObjectTypes.AreaDamage: - distance = 0.0f; - break; - case GameObjectTypes.QuestGiver: - case GameObjectTypes.Text: - case GameObjectTypes.FlagStand: - case GameObjectTypes.FlagDrop: - case GameObjectTypes.MiniGame: - distance = 5.5555553f; - break; - case GameObjectTypes.Binder: - distance = 10.0f; - break; - case GameObjectTypes.Chair: - case GameObjectTypes.BarberChair: - distance = 3.0f; - break; - case GameObjectTypes.FishingNode: - distance = 100.0f; - break; - case GameObjectTypes.Camera: - case GameObjectTypes.MapObject: - case GameObjectTypes.DungeonDifficulty: - case GameObjectTypes.DestructibleBuilding: - case GameObjectTypes.Door: - default: - distance = 5.0f; - break; - - // Following values are not blizzlike - case GameObjectTypes.Mailbox: - // Successful mailbox interaction is rather critical to the client, failing it will start a minute-long cooldown until the next mail query may be executed. - // And since movement info update is not sent with mailbox interaction query, server may find the player outside of interaction range. Thus we increase it. - distance = 10.0f; // 5.0f is blizzlike - break; - } - - return IsAtInteractDistance(player, distance); + return IsAtInteractDistance(player, GetInteractionDistance()); } bool IsAtInteractDistance(Position pos, float radius) @@ -2329,17 +2288,22 @@ namespace Game.Entities float maxY = displayInfo.GeoBoxMax.Y * scale + radius; float maxZ = displayInfo.GeoBoxMax.Z * scale + radius; - Quaternion localRotation = GetLocalRotation(); + Quaternion worldRotation = GetLocalRotation(); //Todo Test this. Needs checked. - var worldSpaceBox = MathFunctions.toWorldSpace(Matrix4x4.CreateFromQuaternion(localRotation), new Vector3(GetPositionX(), GetPositionY(), GetPositionZ()), new Box(new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ))); + var worldSpaceBox = MathFunctions.toWorldSpace(Matrix4x4.CreateFromQuaternion(worldRotation), new Vector3(GetPositionX(), GetPositionY(), GetPositionZ()), new Box(new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ))); return worldSpaceBox.Contains(new Vector3(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ())); } return GetExactDist(pos) <= radius; } - SpellInfo GetSpellForLock(Player player) + public bool IsWithinDistInMap(Player player) + { + return IsInMap(player) && IsInPhase(player) && IsAtInteractDistance(player); + } + + public SpellInfo GetSpellForLock(Player player) { if (!player) return null; @@ -2357,7 +2321,7 @@ namespace Game.Entities if (lockEntry.LockType[i] == 0) continue; - if (lockEntry.LockType[i] == (byte)LockKeyType.Skill) + if (lockEntry.LockType[i] == (byte)LockKeyType.Spell) { SpellInfo spell = Global.SpellMgr.GetSpellInfo((uint)lockEntry.Index[i], GetMap().GetDifficultyID()); if (spell != null) @@ -2807,14 +2771,33 @@ namespace Game.Entities { switch (GetGoType()) { - // @todo find out how the client calculates the maximal usage distance to spellless working - // gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number + case GameObjectTypes.AreaDamage: + return 0.0f; + case GameObjectTypes.QuestGiver: + case GameObjectTypes.Text: + case GameObjectTypes.FlagStand: + case GameObjectTypes.FlagDrop: + case GameObjectTypes.MiniGame: + return 5.5555553f; + case GameObjectTypes.Chair: + case GameObjectTypes.BarberChair: + return 3.0f; + case GameObjectTypes.FishingNode: + return 100.0f; + case GameObjectTypes.FishingHole: + return 20.0f + SharedConst.ContactDistance; // max spell range + case GameObjectTypes.Camera: + case GameObjectTypes.MapObject: + case GameObjectTypes.DungeonDifficulty: + case GameObjectTypes.DestructibleBuilding: + case GameObjectTypes.Door: + return 5.0f; + // Following values are not blizzlike case GameObjectTypes.GuildBank: case GameObjectTypes.Mailbox: - return 10.0f; - case GameObjectTypes.FishingHole: - case GameObjectTypes.FishingNode: - return 20.0f + SharedConst.ContactDistance; // max spell range + // Successful mailbox interaction is rather critical to the client, failing it will start a minute-long cooldown until the next mail query may be executed. + // And since movement info update is not sent with mailbox interaction query, server may find the player outside of interaction range. Thus we increase it. + return 10.0f; // 5.0f is blizzlike default: return SharedConst.InteractionDistance; } diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index f0a281aa6..58bb2379b 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -6029,7 +6029,7 @@ namespace Game.Entities } else { - if (lootType != LootType.Fishinghole && ((lootType != LootType.Fishing && lootType != LootType.FishingJunk) || go.GetOwnerGUID() != GetGUID()) && !go.IsWithinDistInMap(this, SharedConst.InteractionDistance)) + if (lootType != LootType.Fishinghole && ((lootType != LootType.Fishing && lootType != LootType.FishingJunk) || go.GetOwnerGUID() != GetGUID()) && !go.IsWithinDistInMap(this)) return true; if (lootType == LootType.Corpse && go.GetRespawnTime() != 0 && go.IsSpawnedByDefault()) diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 11be02d5c..32ae47fd3 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -5405,7 +5405,7 @@ namespace Game.Entities if (go == null) return null; - if (!go.IsWithinDistInMap(this, go.GetInteractionDistance())) + if (!go.IsWithinDistInMap(this)) return null; return go; diff --git a/Source/Game/Handlers/LootHandler.cs b/Source/Game/Handlers/LootHandler.cs index 5222db8d2..fb34afa31 100644 --- a/Source/Game/Handlers/LootHandler.cs +++ b/Source/Game/Handlers/LootHandler.cs @@ -47,7 +47,7 @@ namespace Game GameObject go = player.GetMap().GetGameObject(lguid); // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player, SharedConst.InteractionDistance))) + if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player))) { player.SendLootRelease(lguid); continue; @@ -129,7 +129,7 @@ namespace Game GameObject go = player.GetMap().GetGameObject(guid); // do not check distance for GO if player is the owner of it (ex. fishing bobber) - if (go && ((go.GetOwnerGUID() == player.GetGUID() || go.IsWithinDistInMap(player, SharedConst.InteractionDistance)))) + if (go && (go.GetOwnerGUID() == player.GetGUID() || go.IsWithinDistInMap(player))) loot = go.loot; break; @@ -331,7 +331,7 @@ namespace Game GameObject go = player.GetMap().GetGameObject(lguid); // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player, SharedConst.InteractionDistance))) + if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player))) return; loot = go.loot; diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index 2e7806976..923da5b6d 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -297,9 +297,36 @@ namespace Game caster = GetPlayer(); } + TriggerCastFlags triggerFlag = TriggerCastFlags.None; + + // client provided targets + SpellCastTargets targets = new(caster, cast.Cast); + // check known spell or raid marker spell (which not requires player to know it) if (caster.IsTypeId(TypeId.Player) && !caster.ToPlayer().HasActiveSpell(spellInfo.Id) && !spellInfo.HasEffect(SpellEffectName.ChangeRaidMarker) && !spellInfo.HasAttribute(SpellAttr8.RaidMarker)) - return; + { + bool allow = false; + + + // allow casting of unknown spells for special lock cases + GameObject go = targets.GetGOTarget(); + if (go != null) + if (go.GetSpellForLock(caster.ToPlayer()) == spellInfo) + allow = true; + + // TODO: Preparation for #23204 + // allow casting of spells triggered by clientside periodic trigger auras + /* + if (caster->HasAuraTypeWithTriggerSpell(SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT, spellId)) + { + allow = true; + triggerFlag = TRIGGERED_FULL_MASK; + } + */ + + if (!allow) + return; + } // Check possible spell cast overrides spellInfo = caster.GetCastSpellInfo(spellInfo); @@ -308,9 +335,6 @@ namespace Game if (GetPlayer().IsPossessing()) return; - // client provided targets - SpellCastTargets targets = new(caster, cast.Cast); - // Client is resending autoshot cast opcode when other spell is cast during shoot rotation // Skip it to prevent "interrupt" message // Also check targets! target may have changed and we need to interrupt current spell @@ -335,7 +359,7 @@ namespace Game if (cast.Cast.MoveUpdate.HasValue) HandleMovementOpcode(ClientOpcodes.MoveStop, cast.Cast.MoveUpdate.Value); - Spell spell = new(caster, spellInfo, TriggerCastFlags.None); + Spell spell = new(caster, spellInfo, triggerFlag); SpellPrepare spellPrepare = new(); spellPrepare.ClientCastID = cast.Cast.CastID; diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 9c7ab8f5a..e9f41f80f 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -6892,6 +6892,11 @@ namespace Game.Spells return SpellCastResult.SpellCastOk; } + case LockKeyType.Spell: + if (m_spellInfo.Id == lockInfo.Index[j]) + return SpellCastResult.SpellCastOk; + reqKey = true; + break; } }