From 27c1fd6aee27bc44f19f34f1af5e42a82d87234c Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Sun, 20 Sep 2020 23:27:13 +0200 Subject: [PATCH] Core/Movement: implement cyclic spline database support --- .../world/4.3.4/2020_09_20_01_world.sql | 7 + .../Database/Implementation/WorldDatabase.cpp | 4 +- src/server/game/AI/CreatureAIRegistry.cpp | 2 + src/server/game/AI/SmartScripts/SmartAI.cpp | 2 + .../game/Entities/Creature/Creature.cpp | 11 +- src/server/game/Entities/Creature/Creature.h | 4 + .../game/Entities/Creature/CreatureData.h | 3 +- src/server/game/Globals/ObjectMgr.cpp | 73 +++++---- src/server/game/Movement/MotionMaster.cpp | 12 +- src/server/game/Movement/MotionMaster.h | 6 +- .../CyclicMovementGenerator.cpp | 141 ++++++++++++++++++ .../CyclicMovementGenerator.h | 58 +++++++ src/server/scripts/Commands/cs_wp.cpp | 2 +- 13 files changed, 288 insertions(+), 37 deletions(-) create mode 100644 sql/updates/world/4.3.4/2020_09_20_01_world.sql create mode 100644 src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.cpp create mode 100644 src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.h diff --git a/sql/updates/world/4.3.4/2020_09_20_01_world.sql b/sql/updates/world/4.3.4/2020_09_20_01_world.sql new file mode 100644 index 0000000000..8d53d2b507 --- /dev/null +++ b/sql/updates/world/4.3.4/2020_09_20_01_world.sql @@ -0,0 +1,7 @@ +ALTER TABLE `creature_addon` + CHANGE `path_id` `waypointPathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL, + ADD COLUMN `cyclicSplinePathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL AFTER `waypointPathId`; + +ALTER TABLE `creature_template_addon` + CHANGE `path_id` `waypointPathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL, + ADD COLUMN `cyclicSplinePathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL AFTER `waypointPathId`; diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 650441227b..12a039d629 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -62,8 +62,8 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID, "SELECT wpguid FROM waypoint_data WHERE id = ? and wpguid <> 0", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_ACTION, "SELECT DISTINCT action FROM waypoint_data", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPTS_MAX_ID, "SELECT MAX(guid) FROM waypoint_scripts", CONNECTION_SYNCH); - PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, path_id) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET path_id = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, waypointPathId) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET waypointPathId = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_CREATURE_ADDON, "DELETE FROM creature_addon WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_CREATURE_ADDON_BY_GUID, "SELECT guid FROM creature_addon WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_INS_WAYPOINT_SCRIPT, "INSERT INTO waypoint_scripts (guid) VALUES (?)", CONNECTION_ASYNC); diff --git a/src/server/game/AI/CreatureAIRegistry.cpp b/src/server/game/AI/CreatureAIRegistry.cpp index 10a06384f4..daf98803a9 100644 --- a/src/server/game/AI/CreatureAIRegistry.cpp +++ b/src/server/game/AI/CreatureAIRegistry.cpp @@ -26,6 +26,7 @@ #include "SmartAI.h" #include "TotemAI.h" +#include "CyclicMovementGenerator.h" #include "MovementGenerator.h" #include "RandomMovementGenerator.h" #include "WaypointMovementGenerator.h" @@ -56,5 +57,6 @@ namespace AIRegistry (new IdleMovementFactory())->RegisterSelf(); (new MovementGeneratorFactory>(RANDOM_MOTION_TYPE))->RegisterSelf(); (new MovementGeneratorFactory>(WAYPOINT_MOTION_TYPE))->RegisterSelf(); + (new MovementGeneratorFactory>(CYCLIC_SPLINE_MOTION_TYPE))->RegisterSelf(); } } diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 680a2b86c5..15dd35dc65 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -603,6 +603,8 @@ void SmartAI::JustReachedHome() { if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != WAYPOINT_MOTION_TYPE && me->GetWaypointPath()) me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true); + else if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != CYCLIC_SPLINE_MOTION_TYPE && me->GetCyclicSplinePathId()) + me->GetMotionMaster()->MoveCyclicPath(me->GetCyclicSplinePathId()); else me->ResumeMovement(); } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 89157716d5..3eb248ba41 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -264,7 +264,7 @@ m_lootRecipient(), m_lootRecipientGroup(0), _skinner(), _pickpocketLootRestore(0 m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(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_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_AI_locked(false), 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_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), _cyclicSplinePathId(0), m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false) { m_valuesCount = UNIT_END; @@ -2595,9 +2595,12 @@ bool Creature::LoadCreaturesAddon() if (cainfo->visibilityDistanceType != VisibilityDistanceType::Normal) SetVisibilityDistanceOverride(cainfo->visibilityDistanceType); - // Load Path - if (cainfo->path_id != 0) - _waypointPathId = cainfo->path_id; + // Load pathing data + if (cainfo->waypointPathId) + _waypointPathId = cainfo->waypointPathId; + + if (cainfo->cyclicSplinePathId) + _cyclicSplinePathId = cainfo->cyclicSplinePathId; if (!cainfo->auras.empty()) { diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 4453cd1a11..19531e186b 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -306,6 +306,8 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma uint32 GetWaypointPath() const { return _waypointPathId; } void LoadPath(uint32 pathid) { _waypointPathId = pathid; } + uint32 GetCyclicSplinePathId() const { return _cyclicSplinePathId; } + // nodeId, pathId std::pair GetCurrentWaypointInfo() const { return _currentWaypointNodeInfo; } void UpdateCurrentWaypointInfo(uint32 nodeId, uint32 pathId) { _currentWaypointNodeInfo = { nodeId, pathId }; } @@ -426,6 +428,8 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma uint32 _waypointPathId; std::pair _currentWaypointNodeInfo; + // Cyclic spline path + uint32 _cyclicSplinePathId; //Formation var CreatureGroup* m_formation; diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index ebd2560257..d3601605da 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -327,7 +327,8 @@ enum InhabitTypeValues // `creature_addon` table struct CreatureAddon { - uint32 path_id; + uint32 waypointPathId; + uint32 cyclicSplinePathId; uint32 mount; uint32 bytes1; uint32 bytes2; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 373200a037..2b17c5cadf 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -563,8 +563,8 @@ void ObjectMgr::LoadCreatureTemplateAddons() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult result = WorldDatabase.Query("SELECT entry, path_id, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon"); + // 0 1 2 3 4 5 6 7 8 9 10 11 + QueryResult result = WorldDatabase.Query("SELECT entry, waypointPathId, cyclicSplinePathId, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon"); if (!result) { @@ -587,17 +587,18 @@ void ObjectMgr::LoadCreatureTemplateAddons() CreatureAddon& creatureAddon = _creatureTemplateAddonStore[entry]; - creatureAddon.path_id = fields[1].GetUInt32(); - creatureAddon.mount = fields[2].GetUInt32(); - creatureAddon.bytes1 = fields[3].GetUInt32(); - creatureAddon.bytes2 = fields[4].GetUInt32(); - creatureAddon.emote = fields[5].GetUInt32(); - creatureAddon.aiAnimKit = fields[6].GetUInt16(); - creatureAddon.movementAnimKit = fields[7].GetUInt16(); - creatureAddon.meleeAnimKit = fields[8].GetUInt16(); - creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[9].GetUInt8()); + creatureAddon.waypointPathId = fields[1].GetUInt32(); + creatureAddon.cyclicSplinePathId = fields[2].GetUInt32(); + creatureAddon.mount = fields[3].GetUInt32(); + creatureAddon.bytes1 = fields[4].GetUInt32(); + creatureAddon.bytes2 = fields[5].GetUInt32(); + creatureAddon.emote = fields[6].GetUInt32(); + creatureAddon.aiAnimKit = fields[7].GetUInt16(); + creatureAddon.movementAnimKit = fields[8].GetUInt16(); + creatureAddon.meleeAnimKit = fields[9].GetUInt16(); + creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[10].GetUInt8()); - Tokenizer tokens(fields[10].GetString(), ' '); + Tokenizer tokens(fields[11].GetString(), ' '); uint8 i = 0; creatureAddon.auras.resize(tokens.size()); for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) @@ -1146,8 +1147,8 @@ void ObjectMgr::LoadCreatureAddons() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult result = WorldDatabase.Query("SELECT guid, path_id, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon"); + // 0 1 2 3 4 5 6 7 8 9 10 11 + QueryResult result = WorldDatabase.Query("SELECT guid, waypointPathId, cyclicSplinePathId, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon"); if (!result) { @@ -1171,23 +1172,45 @@ void ObjectMgr::LoadCreatureAddons() CreatureAddon& creatureAddon = _creatureAddonStore[guid]; - creatureAddon.path_id = fields[1].GetUInt32(); - if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.path_id) + creatureAddon.waypointPathId = fields[1].GetUInt32(); + creatureAddon.cyclicSplinePathId = fields[2].GetUInt32(); + + if (creatureAddon.waypointPathId && creatureAddon.cyclicSplinePathId) + { + if (creData->movementType == WAYPOINT_MOTION_TYPE) + { + creatureAddon.cyclicSplinePathId = 0; + TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has a waypoint and cyclic spline path at the same time but uses WAYPOINT_MOTION_TYPE. Prefered waypoint path", guid); + } + else if (creData->movementType == CYCLIC_SPLINE_MOTION_TYPE) + { + creatureAddon.waypointPathId = 0; + TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has a waypoint and cyclic spline path at the same time but uses CYCLIC_SPLINE_MOTION_TYPE. Prefered cyclic spline path", guid); + } + } + + if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.waypointPathId) { const_cast(creData)->movementType = IDLE_MOTION_TYPE; TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has movement type set to WAYPOINT_MOTION_TYPE but no path assigned", guid); } - creatureAddon.mount = fields[2].GetUInt32(); - creatureAddon.bytes1 = fields[3].GetUInt32(); - creatureAddon.bytes2 = fields[4].GetUInt32(); - creatureAddon.emote = fields[5].GetUInt32(); - creatureAddon.aiAnimKit = fields[6].GetUInt16(); - creatureAddon.movementAnimKit = fields[7].GetUInt16(); - creatureAddon.meleeAnimKit = fields[8].GetUInt16(); - creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[9].GetUInt8()); + if (creData->movementType == CYCLIC_SPLINE_MOTION_TYPE && !creatureAddon.cyclicSplinePathId) + { + const_cast(creData)->movementType = IDLE_MOTION_TYPE; + TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has movement type set to CYCLIC_SPLINE_MOTION_TYPE but no path assigned", guid); + } - Tokenizer tokens(fields[10].GetString(), ' '); + creatureAddon.mount = fields[3].GetUInt32(); + creatureAddon.bytes1 = fields[4].GetUInt32(); + creatureAddon.bytes2 = fields[5].GetUInt32(); + creatureAddon.emote = fields[6].GetUInt32(); + creatureAddon.aiAnimKit = fields[7].GetUInt16(); + creatureAddon.movementAnimKit = fields[8].GetUInt16(); + creatureAddon.meleeAnimKit = fields[9].GetUInt16(); + creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[10].GetUInt8()); + + Tokenizer tokens(fields[11].GetString(), ' '); uint8 i = 0; creatureAddon.auras.resize(tokens.size()); for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 69b793dbc8..68a3091b95 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -20,6 +20,7 @@ #include "ConfusedMovementGenerator.h" #include "Creature.h" #include "CreatureAISelector.h" +#include "CyclicMovementGenerator.h" #include "DBCStores.h" #include "G3DPosition.hpp" #include "FleeingMovementGenerator.h" @@ -42,6 +43,7 @@ #include "Unit.h" #include "WaypointDefines.h" #include "WaypointMovementGenerator.h" +#include "WaypointManager.h" inline MovementGenerator* GetIdleMovementGenerator() { @@ -498,7 +500,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool if (velocity > 0.f) init.SetVelocity(velocity); - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_ACTIVE); + Mutate(new GenericMovementGenerator(std::move(init), CYCLIC_SPLINE_MOTION_TYPE, 0), MOTION_SLOT_ACTIVE); } void MotionMaster::MoveCyclicPath(Position const* pathPoints, size_t pathSize, bool walk /*= false*/, bool fly /*= false*/, float velocity /*= 0.0f*/) @@ -524,7 +526,13 @@ void MotionMaster::MoveCyclicPath(Position const* pathPoints, size_t pathSize, b init.SetSmooth(); init.SetWalk(walk); init.SetCyclic(); - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_IDLE); + Mutate(new GenericMovementGenerator(std::move(init), CYCLIC_SPLINE_MOTION_TYPE, 0), MOTION_SLOT_IDLE); +} + +void MotionMaster::MoveCyclicPath(uint32 pathId) +{ + if (WaypointPath const* splinePath = sWaypointMgr->GetPath(pathId)) + Mutate(new CyclicMovementGenerator(splinePath), MOTION_SLOT_IDLE); } void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk /*= false*/, bool fly /*= false*/, float velocity /*= 0.0f*/) diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index de4b08b15d..34304a596c 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -49,7 +49,8 @@ enum MovementGeneratorType : uint8 IDLE_MOTION_TYPE = 0, // IdleMovementGenerator.h RANDOM_MOTION_TYPE = 1, // RandomMovementGenerator.h WAYPOINT_MOTION_TYPE = 2, // WaypointMovementGenerator.h - MAX_DB_MOTION_TYPE = 3, // Below motion types can't be set in DB. + CYCLIC_SPLINE_MOTION_TYPE = 3, // CyclicMovementGenerator.h + MAX_DB_MOTION_TYPE = 4, // Below motion types can't be set in DB. CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h @@ -60,7 +61,7 @@ enum MovementGeneratorType : uint8 ASSISTANCE_MOTION_TYPE = 11, // PointMovementGenerator.h ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h - FOLLOW_MOTION_TYPE = 14, + FOLLOW_MOTION_TYPE = 14, // FollowMovementGenerator.h ROTATE_MOTION_TYPE = 15, EFFECT_MOTION_TYPE = 16, SPLINE_CHAIN_MOTION_TYPE = 17, // SplineChainMovementGenerator.h @@ -182,6 +183,7 @@ class TC_GAME_API MotionMaster void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false); void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount, float velocity = 0.f); void MoveCyclicPath(Position const* pathPoints, size_t pathSize, bool walk = false, bool fly = false, float velocity = 0.f); + void MoveCyclicPath(uint32 pathId); void MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk = false, bool fly = false, float velocity = 0.f); // Walk along spline chain stored in DB (script_spline_chain_meta and script_spline_chain_waypoints) void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk); diff --git a/src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.cpp new file mode 100644 index 0000000000..24b3d7e428 --- /dev/null +++ b/src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.cpp @@ -0,0 +1,141 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "CyclicMovementGenerator.h" +#include "Creature.h" +#include "CreatureAI.h" +#include "G3DPosition.hpp" +#include "Log.h" +#include "Map.h" +#include "MoveSpline.h" +#include "MoveSplineInit.h" +#include "ObjectMgr.h" +#include "Transport.h" +#include "WaypointManager.h" + +inline bool CanMove(Creature const* creature) +{ + return (!creature->HasUnitState(UNIT_STATE_NOT_MOVE) && !creature->IsMovementPreventedByCasting()); +} + +CyclicMovementGenerator::CyclicMovementGenerator(WaypointPath const* path, Optional enforceFlight, Optional enforceWalk, Optional velocity) : _path(path), _moveTimer(0) +{ + if (enforceFlight.is_initialized()) + _enforceFlight = *enforceFlight; + + if (enforceWalk.is_initialized()) + _enforceWalk = *enforceWalk; + + if (velocity.is_initialized()) + _velocity = *velocity; +} + +CyclicMovementGenerator::CyclicMovementGenerator() : _path(nullptr), _moveTimer(0) +{ +} + +void CyclicMovementGenerator::DoInitialize(Creature* creature) +{ + if (!_path) + if (uint32 pathId = creature->GetCyclicSplinePathId()) + _path = sWaypointMgr->GetPath(pathId); + + if (_path) + _moveTimer.Reset(1000); +} + +void CyclicMovementGenerator::DoFinalize(Creature* creature) +{ + creature->setActive(false); +} + +void CyclicMovementGenerator::DoReset(Creature* creature) +{ + if (_moveTimer.Passed() && CanMove(creature)) + StartMovement(creature); +} + +bool CyclicMovementGenerator::DoUpdate(Creature* creature, uint32 diff) +{ + if (!creature || !creature->IsAlive()) + return true; + + if (!_path || _path->nodes.empty()) + return true; + + if (!CanMove(creature)) + { + creature->StopMoving(); + return true; + } + + // dont update wait timer while moving + if (creature->movespline->Finalized()) + { + _moveTimer.Update(diff); + if (_moveTimer.Passed()) + { + _moveTimer.Reset(0); + StartMovement(creature); + } + } + + return true; +} + +void CyclicMovementGenerator::StartMovement(Creature* creature) +{ + if (!creature || !creature->IsAlive() || !CanMove(creature) || !_path || _path->nodes.empty()) + return; + + if (!CanMove(creature) || (creature->IsFormationLeader() && !creature->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation + { + _moveTimer.Reset(1000); // delay 1s + return; + } + + // Cyclic splines get asynchronous if the serverside position is not being tracked constantly. + creature->setActive(true); + + bool const flying = creature->IsFlying() || creature->IsInWater(); // Swimming units also use flying and uncompressed splines + Movement::MoveSplineInit init(creature); + Movement::PointsArray path; + + path.reserve(_path->nodes.size() + 1); + path.push_back(PositionToVector3(creature->GetPosition())); + std::transform(_path->nodes.begin(), _path->nodes.end(), std::back_inserter(path), [](WaypointNode const& node) + { + return G3D::Vector3(node.x, node.y, node.z); + }); + + if (flying || (_enforceFlight.is_initialized() && *_enforceFlight)) + { + init.SetFly(); + init.SetUncompressed(); + } + + if (_velocity.is_initialized()) + init.SetVelocity(*_velocity); + + if (_enforceWalk.is_initialized()) + init.SetWalk(*_enforceWalk); + + init.MovebyPath(path); + init.SetSmooth(); + init.SetCyclic(); + init.Launch(); +} diff --git a/src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.h b/src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.h new file mode 100644 index 0000000000..21e91fd7d0 --- /dev/null +++ b/src/server/game/Movement/MovementGenerators/CyclicMovementGenerator.h @@ -0,0 +1,58 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef TRINITY_CYCLICMOVEMENTGENERATOR_H +#define TRINITY_CYCLICMOVEMENTGENERATOR_H + +#include "MovementGenerator.h" +#include "Timer.h" +#include "OptionalFwd.h" + +enum MovementGeneratorType : uint8; + +class Creature; +struct WaypointPath; + +template +class CyclicMovementGenerator; + +template<> +class CyclicMovementGenerator : public MovementGeneratorMedium> +{ + public: + explicit CyclicMovementGenerator(WaypointPath const* path, Optional enforceFlight = { }, Optional enforceWalk = { }, Optional velocity = { }); + explicit CyclicMovementGenerator(); + + void DoInitialize(Creature*); + void DoFinalize(Creature*); + void DoReset(Creature*); + bool DoUpdate(Creature*, uint32); + + MovementGeneratorType GetMovementGeneratorType() const override { return CYCLIC_SPLINE_MOTION_TYPE; } + + private: + void StartMovement(Creature*); + + WaypointPath const* _path; + Optional _enforceFlight; + Optional _enforceWalk; + Optional _velocity; + + TimeTrackerSmall _moveTimer; +}; + +#endif // TRINITY_CYCLICMOVEMENTGENERATOR_H diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index f85fb5cd09..0ae2d31e1d 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -260,7 +260,7 @@ public: } CreatureAddon const* addon = sObjectMgr->GetCreatureAddon(guidLow); - if (!addon || addon->path_id == 0) + if (!addon || addon->waypointPathId == 0) { handler->PSendSysMessage("%s%s|r", "|cffff33ff", "Target does not have a loaded path."); return true;