diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index 390702ac4..42bad3243 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -360,6 +360,9 @@ namespace Game.Entities } LastUsedScriptID = GetGoInfo().ScriptId; + + m_stringIds[0] = goInfo.StringId; + AIM_Initialize(); if (spawnid != 0) @@ -1161,6 +1164,8 @@ namespace Game.Entities m_goData = data; + m_stringIds[1] = data.StringId; + if (addToMap && !GetMap().AddToMap(this)) return false; @@ -2636,6 +2641,27 @@ namespace Game.Entities return GetGoInfo().ScriptId; } + public bool HasStringId(string id) + { + return m_stringIds.Contains(id); + } + + public void SetScriptStringId(string id) + { + if (!id.IsEmpty()) + { + m_scriptStringId = id; + m_stringIds[2] = m_scriptStringId; + } + else + { + m_scriptStringId = null; + m_stringIds[2] = null; + } + } + + public string[] GetStringIds() { return m_stringIds; } + public override string GetName(Locale locale = Locale.enUS) { if (locale != Locale.enUS) @@ -3769,6 +3795,8 @@ namespace Game.Entities public GameObjectFieldData m_gameObjectData; GameObjectTypeBase m_goTypeImpl; protected GameObjectValue m_goValue; // TODO: replace with m_goTypeImpl + string[] m_stringIds = new string[3]; + string m_scriptStringId; protected GameObjectTemplate m_goInfo; protected GameObjectTemplateAddon m_goTemplateAddon; GameObjectData m_goData; diff --git a/Source/Game/Entities/GameObject/GameObjectData.cs b/Source/Game/Entities/GameObject/GameObjectData.cs index 11eba7cc6..16244af4d 100644 --- a/Source/Game/Entities/GameObject/GameObjectData.cs +++ b/Source/Game/Entities/GameObject/GameObjectData.cs @@ -48,180 +48,183 @@ namespace Game.Entities public uint ScriptId; [FieldOffset(68)] + public string StringId; + + [FieldOffset(72)] public door Door; - [FieldOffset(68)] + [FieldOffset(72)] public button Button; - [FieldOffset(68)] + [FieldOffset(72)] public questgiver QuestGiver; - [FieldOffset(68)] + [FieldOffset(72)] public chest Chest; - [FieldOffset(68)] + [FieldOffset(72)] public binder Binder; - [FieldOffset(68)] + [FieldOffset(72)] public generic Generic; - [FieldOffset(68)] + [FieldOffset(72)] public trap Trap; - [FieldOffset(68)] + [FieldOffset(72)] public chair Chair; - [FieldOffset(68)] + [FieldOffset(72)] public spellFocus SpellFocus; - [FieldOffset(68)] + [FieldOffset(72)] public text Text; - [FieldOffset(68)] + [FieldOffset(72)] public goober Goober; - [FieldOffset(68)] + [FieldOffset(72)] public transport Transport; - [FieldOffset(68)] + [FieldOffset(72)] public areadamage AreaDamage; - [FieldOffset(68)] + [FieldOffset(72)] public camera Camera; - [FieldOffset(68)] + [FieldOffset(72)] public moTransport MoTransport; - [FieldOffset(68)] + [FieldOffset(72)] public duelflag DuelFlag; - [FieldOffset(68)] + [FieldOffset(72)] public fishingnode FishingNode; - [FieldOffset(68)] + [FieldOffset(72)] public ritual Ritual; - [FieldOffset(68)] + [FieldOffset(72)] public mailbox MailBox; - [FieldOffset(68)] + [FieldOffset(72)] public guardpost GuardPost; - [FieldOffset(68)] + [FieldOffset(72)] public spellcaster SpellCaster; - [FieldOffset(68)] + [FieldOffset(72)] public meetingstone MeetingStone; - [FieldOffset(68)] + [FieldOffset(72)] public flagstand FlagStand; - [FieldOffset(68)] + [FieldOffset(72)] public fishinghole FishingHole; - [FieldOffset(68)] + [FieldOffset(72)] public flagdrop FlagDrop; - [FieldOffset(68)] + [FieldOffset(72)] public controlzone ControlZone; - [FieldOffset(68)] + [FieldOffset(72)] public auraGenerator AuraGenerator; - [FieldOffset(68)] + [FieldOffset(72)] public dungeonDifficulty DungeonDifficulty; - [FieldOffset(68)] + [FieldOffset(72)] public barberChair BarberChair; - [FieldOffset(68)] + [FieldOffset(72)] public destructiblebuilding DestructibleBuilding; - [FieldOffset(68)] + [FieldOffset(72)] public guildbank GuildBank; - [FieldOffset(68)] + [FieldOffset(72)] public trapDoor TrapDoor; - [FieldOffset(68)] + [FieldOffset(72)] public newflag NewFlag; - [FieldOffset(68)] + [FieldOffset(72)] public newflagdrop NewFlagDrop; - [FieldOffset(68)] + [FieldOffset(72)] public garrisonbuilding GarrisonBuilding; - [FieldOffset(68)] + [FieldOffset(72)] public garrisonplot GarrisonPlot; - [FieldOffset(68)] + [FieldOffset(72)] public clientcreature ClientCreature; - [FieldOffset(68)] + [FieldOffset(72)] public clientitem ClientItem; - [FieldOffset(68)] + [FieldOffset(72)] public capturepoint CapturePoint; - [FieldOffset(68)] + [FieldOffset(72)] public phaseablemo PhaseableMO; - [FieldOffset(68)] + [FieldOffset(72)] public garrisonmonument GarrisonMonument; - [FieldOffset(68)] + [FieldOffset(72)] public garrisonshipment GarrisonShipment; - [FieldOffset(68)] + [FieldOffset(72)] public garrisonmonumentplaque GarrisonMonumentPlaque; - [FieldOffset(68)] + [FieldOffset(72)] public itemforge ItemForge; - [FieldOffset(68)] + [FieldOffset(72)] public uilink UILink; - [FieldOffset(68)] + [FieldOffset(72)] public keystonereceptacle KeystoneReceptacle; - [FieldOffset(68)] + [FieldOffset(72)] public gatheringnode GatheringNode; - [FieldOffset(68)] + [FieldOffset(72)] public challengemodereward ChallengeModeReward; - [FieldOffset(68)] + [FieldOffset(72)] public multi Multi; - [FieldOffset(68)] + [FieldOffset(72)] public siegeableMulti SiegeableMulti; - [FieldOffset(68)] + [FieldOffset(72)] public siegeableMO SiegeableMO; - [FieldOffset(68)] + [FieldOffset(72)] public pvpReward PvpReward; - [FieldOffset(68)] + [FieldOffset(72)] public playerchoicechest PlayerChoiceChest; - [FieldOffset(68)] + [FieldOffset(72)] public legendaryforge LegendaryForge; - [FieldOffset(68)] + [FieldOffset(72)] public garrtalenttree GarrTalentTree; - [FieldOffset(68)] + [FieldOffset(72)] public weeklyrewardchest WeeklyRewardChest; - [FieldOffset(68)] + [FieldOffset(72)] public clientmodel ClientModel; - [FieldOffset(68)] + [FieldOffset(72)] public craftingTable CraftingTable; - [FieldOffset(68)] + [FieldOffset(72)] public raw Raw; [FieldOffset(208)] diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index bead19d40..8fb9ee8b0 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1683,6 +1683,18 @@ namespace Game.Entities return searcher.GetTarget(); } + GameObject FindNearestGameObjectWithOptions(float range, FindGameObjectOptions options) + { + NearestCheckCustomizer checkCustomizer = new(this, range); + GameObjectWithOptionsInObjectRangeCheck checker = new(this, checkCustomizer, options); + GameObjectLastSearcher searcher = new(this, checker); + if (options.IgnorePhases) + searcher.i_phaseShift = PhasingHandler.GetAlwaysVisiblePhaseShift(); + + Cell.VisitGridObjects(this, searcher, range); + return searcher.GetTarget(); + } + public GameObject FindNearestUnspawnedGameObject(uint entry, float range) { NearestUnspawnedGameObjectEntryInObjectRangeCheck checker = new(this, entry, range); @@ -2834,6 +2846,17 @@ namespace Game.Entities return gameobjectList; } + void GetGameObjectListWithOptionsInGrid(List gameObjectContainer, float maxSearchRange, FindGameObjectOptions options) + { + InRangeCheckCustomizer checkCustomizer = new(this, maxSearchRange); + GameObjectWithOptionsInObjectRangeCheck check = new(this, checkCustomizer, options); + GameObjectListSearcher searcher = new(this, gameObjectContainer, check); + if (options.IgnorePhases) + searcher.i_phaseShift = PhasingHandler.GetAlwaysVisiblePhaseShift(); + + Cell.VisitGridObjects(this, searcher, maxSearchRange); + } + public List GetCreatureListWithEntryInGrid(uint entry = 0, float maxSearchRange = 250.0f) { List creatureList = new(); @@ -2847,8 +2870,8 @@ namespace Game.Entities public List GetCreatureListWithOptionsInGrid(float maxSearchRange, FindCreatureOptions options) { List creatureList = new(); - NoopCheckCustomizer checkCustomizer = new(); - CreatureWithOptionsInObjectRangeCheck check = new(this, checkCustomizer, options); + InRangeCheckCustomizer checkCustomizer = new(this, maxSearchRange); + CreatureWithOptionsInObjectRangeCheck check = new(this, checkCustomizer, options); CreatureListSearcher searcher = new(this, creatureList, check); if (options.IgnorePhases) searcher.i_phaseShift = PhasingHandler.GetAlwaysVisiblePhaseShift(); @@ -4038,4 +4061,20 @@ namespace Game.Entities public ObjectGuid? DemonCreatorGuid; public ObjectGuid? PrivateObjectOwnerGuid; } + + class FindGameObjectOptions + { + public uint? GameObjectId; + public string StringId; + + public bool? IsSummon; + public bool? IsSpawned; + + public bool IgnorePhases; + public bool IgnoreNotOwnedPrivateObjects = true; + public bool IgnorePrivateObjects; + + public ObjectGuid? OwnerGuid; + public ObjectGuid? PrivateObjectOwnerGuid; + } } \ No newline at end of file diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 1aaea2551..2d12f2660 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -3971,8 +3971,8 @@ namespace Game "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 34 35 36 "Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, Data24, Data25, Data26, Data27, Data28, " + - //37 38 39 40 41 42 43 44 45 - "Data29, Data30, Data31, Data32, Data33, Data34, ContentTuningId, AIName, ScriptName FROM gameobject_template"); + //37 38 39 40 41 42 43 44 45 46 + "Data29, Data30, Data31, Data32, Data33, Data34, ContentTuningId, AIName, ScriptName, StringId FROM gameobject_template"); if (result.IsEmpty()) { @@ -4004,6 +4004,7 @@ namespace Game got.ContentTuningId = result.Read(43); got.AIName = result.Read(44); got.ScriptId = GetScriptId(result.Read(45)); + got.StringId = result.Read(46); switch (got.type) { @@ -4264,8 +4265,8 @@ namespace Game SQLResult result = DB.World.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, " + //7 8 9 10 11 12 13 14 15 16 "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnDifficulties, eventEntry, poolSpawnId, " + - //17 18 19 20 21 - "phaseUseFlags, phaseid, phasegroup, terrainSwapMap, ScriptName " + + //17 18 19 20 21 22 + "phaseUseFlags, phaseid, phasegroup, terrainSwapMap, 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"); @@ -4428,6 +4429,7 @@ namespace Game } data.ScriptId = GetScriptId(result.Read(21)); + data.StringId = result.Read(22); if (data.rotation.X < -1.0f || data.rotation.X > 1.0f) { diff --git a/Source/Game/Maps/GridNotifiers.cs b/Source/Game/Maps/GridNotifiers.cs index 174bed823..4569031d6 100644 --- a/Source/Game/Maps/GridNotifiers.cs +++ b/Source/Game/Maps/GridNotifiers.cs @@ -1490,7 +1490,7 @@ namespace Game.Maps public class GameObjectLastSearcher : Notifier { - PhaseShift i_phaseShift; + public PhaseShift i_phaseShift; GameObject i_object; ICheck i_check; @@ -1518,7 +1518,7 @@ namespace Game.Maps public class GameObjectListSearcher : Notifier { - PhaseShift i_phaseShift; + public PhaseShift i_phaseShift; List i_objects; ICheck i_check; @@ -2422,7 +2422,7 @@ namespace Game.Maps float i_range; } - public class CreatureWithOptionsInObjectRangeCheck : ICheck where T : NoopCheckCustomizer + public class CreatureWithOptionsInObjectRangeCheck : ICheck where T : InRangeCheckCustomizer { WorldObject i_obj; FindCreatureOptions i_args; @@ -2482,6 +2482,54 @@ namespace Game.Maps } } + class GameObjectWithOptionsInObjectRangeCheck : ICheck where T : InRangeCheckCustomizer + { + WorldObject _obj; + FindGameObjectOptions _args; + T _customizer; + + public GameObjectWithOptionsInObjectRangeCheck(WorldObject obj, T customizer, FindGameObjectOptions args) + { + _obj = obj; + _args = args; + _customizer = customizer; + } + + public bool Invoke(GameObject go) + { + if (_args.IsSpawned.HasValue && _args.IsSpawned != go.IsSpawned()) // Despawned + return false; + + if (go.GetGUID() == _obj.GetGUID()) + return false; + + if (!_customizer.Test(go)) + return false; + + if (_args.GameObjectId.HasValue && go.GetEntry() != _args.GameObjectId) + return false; + + if (!_args.StringId.IsEmpty() && !go.HasStringId(_args.StringId)) + return false; + + if (_args.IsSummon.HasValue && (go.GetSpawnId() == 0) != _args.IsSummon) + return false; + + if ((_args.OwnerGuid.HasValue && go.GetOwnerGUID() != _args.OwnerGuid) + || (_args.PrivateObjectOwnerGuid.HasValue && go.GetPrivateObjectOwner() != _args.PrivateObjectOwnerGuid)) + return false; + + if (_args.IgnorePrivateObjects && go.IsPrivateObject()) + return false; + + if (_args.IgnoreNotOwnedPrivateObjects && !go.CheckPrivateObjectOwnerVisibility(_obj)) + return false; + + _customizer.Update(go); + return true; + } + } + public class AnyPlayerInObjectRangeCheck : ICheck { public AnyPlayerInObjectRangeCheck(WorldObject obj, float range, bool reqAlive = true) @@ -2933,32 +2981,44 @@ namespace Game.Maps } // CHECK modifiers - public class NoopCheckCustomizer + public class InRangeCheckCustomizer { - public virtual bool Test(WorldObject o) { return true; } + WorldObject _obj; + float _range; + + public InRangeCheckCustomizer(WorldObject obj, float range) + { + _obj = obj; + _range = range; + } + + public virtual bool Test(WorldObject obj) + { + return _obj.IsWithinDist(obj, _range); + } public virtual void Update(WorldObject o) { } } - class NearestCheckCustomizer : NoopCheckCustomizer + class NearestCheckCustomizer : InRangeCheckCustomizer { WorldObject i_obj; float i_range; - public NearestCheckCustomizer(WorldObject obj, float range) + public NearestCheckCustomizer(WorldObject obj, float range) : base(obj, range) { i_obj = obj; i_range = range; } - public override bool Test(WorldObject o) + public override bool Test(WorldObject obj) { - return i_obj.IsWithinDist(o, i_range); + return i_obj.IsWithinDist(obj, i_range); } - public override void Update(WorldObject o) + public override void Update(WorldObject obj) { - i_range = i_obj.GetDistance(o); + i_range = i_obj.GetDistance(obj); } }