TrinityCore
Loading...
Searching...
No Matches
MoveSpline.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "MoveSpline.h"
19#include "Log.h"
20#include "Creature.h"
21
22#include <sstream>
23
24namespace Movement{
25
27{
29
30 float u = 1.f;
31 int32 seg_time = spline.length(point_Idx, point_Idx+1);
32 if (seg_time > 0)
33 u = (time_passed - spline.length(point_Idx)) / (float)seg_time;
34 Location c;
37
39 ;// MoveSplineFlag::Animation disables falling or parabolic movement
40 else if (splineflags.parabolic)
42 else if (splineflags.falling)
44
46 {
49 else if (splineflags.final_point)
50 c.orientation = std::atan2(facing.f.y - c.y, facing.f.x - c.x);
51 //nothing to do for MoveSplineFlag::Final_Target flag
52 }
53 else
54 {
56 {
57 Vector3 hermite;
59 c.orientation = std::atan2(hermite.y, hermite.x);
60 }
61
63 c.orientation = c.orientation - float(M_PI);
64 }
65 return c;
66}
67
69{
71 {
72 float t_passedf = MSToSec(time_passed - effect_start_time);
73 float t_durationf = MSToSec(Duration() - effect_start_time); //client use not modified duration here
74
75 // -a*x*x + bx + c:
76 //(dur * v3->z_acceleration * dt)/2 - (v3->z_acceleration * dt * dt)/2 + Z;
77 el += (t_durationf - t_passedf) * 0.5f * vertical_acceleration * t_passedf;
78 }
79}
80
82{
84 float final_z = FinalDestination().z;
85 el = std::max(z_now, final_z);
86}
87
88inline uint32 computeDuration(float length, float velocity)
89{
90 return SecToMS(length / velocity);
91}
92
94{
95 FallInitializer(float _start_elevation) : start_elevation(_start_elevation) { }
98 {
99 return Movement::computeFallTime(start_elevation - s.getPoint(i+1).z, false) * 1000.f;
100 }
101};
102
103enum{
106
108{
109 CommonInitializer(float _velocity) : velocityInv(1000.f/_velocity), time(minimal_duration) { }
113 {
114 time += (s.SegLength(i) * velocityInv);
115 return time;
116 }
117};
118
120{
122 if (args.flags.cyclic)
123 {
124 uint32 cyclic_point = 0;
126 cyclic_point = 1; // shouldn't be modified, came from client
127 spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point, args.initialOrientation);
128 }
129 else
130 spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], args.initialOrientation);
131
132 // init spline timestamps
134 {
136 spline.initLengths(init);
137 }
138 else
139 {
140 CommonInitializer init(args.velocity);
141 spline.initLengths(init);
142 }
143
146 {
147 TC_LOG_DEBUG("misc", "MoveSpline::init_spline: zero length spline, wrong input data?");
148 spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
149 }
151}
152
154{
155 splineflags = args.flags;
156 facing = args.facing;
157 m_Id = args.splineId;
160
161 time_passed = 0;
164
165 velocity = args.velocity;
166
167 // Check if its a stop spline
168 if (args.flags.done)
169 {
170 spline.clear();
171 return;
172 }
173
174 init_spline(args);
175
176 // init parabolic / animation
177 // spline initialized, duration known and i able to compute parabolic acceleration
179 {
182 {
183 float f_duration = MSToSec(Duration() - effect_start_time);
184 vertical_acceleration = args.parabolic_amplitude * 8.f / (f_duration * f_duration);
185 }
186 }
187}
188
189MoveSpline::MoveSpline() : m_Id(0), time_passed(0),
190 vertical_acceleration(0.f), initialOrientation(0.f), effect_start_time(0), point_Idx(0), point_Idx_offset(0), velocity(0.f),
191 onTransport(false)
192{
193 splineflags.done = true;
194}
195
197
199{
200#define CHECK(exp) \
201 if (!(exp))\
202 {\
203 if (unit)\
204 TC_LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for {}", #exp, unit->GetDebugInfo());\
205 else\
206 TC_LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for cyclic spline continuation", #exp); \
207 return false;\
208 }
209 CHECK(path.size() > 1);
210 CHECK(velocity >= 0.001f);
211 CHECK(time_perc >= 0.f && time_perc <= 1.f);
212 //CHECK(_checkPathBounds());
213 return true;
214#undef CHECK
215}
216
217// MONSTER_MOVE packet format limitation for not CatmullRom movement:
218// each vertex offset packed into 11 bytes
220{
221 constexpr float MIN_XY_OFFSET = -(1 << 11) / 4.0f;
222 constexpr float MIN_Z_OFFSET = -(1 << 10) / 4.0f;
223
224 // positive values have 1 less bit limit (if the highest bit was set, value would be sign extended into negative when decompressing)
225 constexpr float MAX_XY_OFFSET = (1 << 10) / 4.0f;
226 constexpr float MAX_Z_OFFSET = (1 << 9) / 4.0f;
227
228 auto isValidPackedXYOffset = [](float coord) -> bool { return coord > MIN_XY_OFFSET && coord < MAX_XY_OFFSET; };
229 auto isValidPackedZOffset = [](float coord) -> bool { return coord > MIN_Z_OFFSET && coord < MAX_Z_OFFSET; };
230
231 if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2)
232 {
233 Vector3 middle = (path.front() + path.back()) / 2;
234 for (uint32 i = 1; i < path.size() - 1; ++i)
235 {
236 // when compression is enabled, each point coord is packed into 11 bits (10 for Z)
237 if (!isValidPackedXYOffset(middle.x - path[i].x)
238 || !isValidPackedXYOffset(middle.y - path[i].y)
239 || !isValidPackedZOffset(middle.z - path[i].z))
240 {
241 TC_LOG_ERROR("misc", "MoveSplineInitArgs::_checkPathBounds check failed");
242 return false;
243 }
244 }
245 }
246 return true;
247}
248
249MoveSplineInitArgs::MoveSplineInitArgs(size_t path_capacity /*= 16*/) : path_Idx_offset(0), velocity(0.f),
250parabolic_amplitude(0.f), time_perc(0.f), splineId(0), initialOrientation(0.f),
251walk(false), HasVelocity(false), TransformForTransport(true)
252{
253 path.reserve(path_capacity);
254}
255
257
259
261
263{
264 if (Finalized())
265 {
266 ms_time_diff = 0;
267 return Result_Arrived;
268 }
269
270 UpdateResult result = Result_None;
271
272 int32 minimal_diff = std::min(ms_time_diff, segment_time_elapsed());
273 ASSERT(minimal_diff >= 0);
274 time_passed += minimal_diff;
275 ms_time_diff -= minimal_diff;
276
278 {
279 ++point_Idx;
280 if (point_Idx < spline.last())
281 {
282 result = Result_NextSegment;
283 }
284 else
285 {
286 if (spline.isCyclic())
287 {
290 result = Result_NextCycle;
291
292 // Remove first point from the path after one full cycle.
293 // That point was the position of the unit prior to entering the cycle and it shouldn't be repeated with continuous cycles.
295 {
296 splineflags.enter_cycle = false;
297
298 MoveSplineInitArgs args{ (size_t)spline.getPointCount() };
299 args.path.assign(spline.getPoints().begin() + spline.first() + 1, spline.getPoints().begin() + spline.last());
300 args.facing = facing;
301 args.flags = splineflags;
302 args.path_Idx_offset = point_Idx_offset;
303 // MoveSplineFlag::Parabolic | MoveSplineFlag::Animation not supported currently
304 //args.parabolic_amplitude = ?;
305 //args.time_perc = ?;
306 args.splineId = m_Id;
307 args.initialOrientation = initialOrientation;
308 args.velocity = 1.0f; // Calculated below
309 args.HasVelocity = true;
310 args.TransformForTransport = onTransport;
311 if (args.Validate(nullptr))
312 {
313 // New cycle should preserve previous cycle's duration for some weird reason, even though
314 // the path is really different now. Blizzard is weird. Or this was just a simple oversight.
315 // Since our splines precalculate length with velocity in mind, if we want to find the desired
316 // velocity, we have to make a fake spline, calculate its duration and then compare it to the
317 // desired duration, thus finding out how much the velocity has to be increased for them to match.
318 MoveSpline tempSpline;
319 tempSpline.Initialize(args);
320 args.velocity = (float)tempSpline.Duration() / Duration();
321
322 if (args.Validate(nullptr))
323 init_spline(args);
324 }
325 }
326 }
327 else
328 {
329 _Finalize();
330 ms_time_diff = 0;
331 result = Result_Arrived;
332 }
333 }
334 }
335
336 return result;
337}
338
339std::string MoveSpline::ToString() const
340{
341 std::stringstream str;
342 str << "MoveSpline" << std::endl;
343 str << "spline Id: " << GetId() << std::endl;
344 str << "flags: " << splineflags.ToString() << std::endl;
346 str << "facing angle: " << facing.angle << std::endl;
347 else if (splineflags.final_target)
348 str << "facing target: " << facing.target.ToString() << std::endl;
349 else if (splineflags.final_point)
350 str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z << std::endl;
351 str << "time passed: " << time_passed << std::endl;
352 str << "total time: " << Duration() << std::endl;
353 str << "spline point Id: " << point_Idx << std::endl;
354 str << "path point Id: " << currentPathIdx() << std::endl;
355 str << spline.ToString();
356 return str.str();
357}
358
360{
361 splineflags.done = true;
362 point_Idx = spline.last() - 1;
364}
365
367{
368 int32 point = point_Idx_offset + point_Idx - spline.first() + (int)Finalized();
369 if (isCyclic())
370 point = point % (spline.last()-spline.first());
371 return point;
372}
373}
#define M_PI
Definition Common.h:72
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define CHECK(exp)
std::string ToString() const
bool hasFlag(uint32 f) const
int32 next_timestamp() const
Definition MoveSpline.h:83
bool isCyclic() const
Definition MoveSpline.h:122
std::string ToString() const
UpdateResult _updateState(int32 &ms_time_diff)
============================================================================================
Location ComputePosition() const
uint32 GetId() const
Definition MoveSpline.h:120
void computeFallElevation(float &el) const
bool Finalized() const
Definition MoveSpline.h:121
Vector3 FinalDestination() const
Definition MoveSpline.h:124
void Initialize(MoveSplineInitArgs const &)
int32 currentPathIdx() const
int32 Duration() const
Definition MoveSpline.h:89
bool Initialized() const
Definition MoveSpline.h:98
int32 segment_time_elapsed() const
Definition MoveSpline.h:84
void computeParabolicElevation(float &el) const
MoveSplineFlag splineflags
Definition MoveSpline.h:62
void init_spline(MoveSplineInitArgs const &args)
bool isCyclic() const
Definition Spline.h:113
ControlArray const & getPoints() const
Definition Spline.h:115
float SegLength(index_type i) const
Definition Spline.h:133
index_type first() const
Definition Spline.h:108
Vector3 const & getPoint(index_type i) const
Definition Spline.h:117
index_type last() const
Definition Spline.h:109
std::string ToString() const
Definition Spline.cpp:292
index_type getPointCount() const
Definition Spline.h:116
void init_spline(const Vector3 *controls, index_type count, EvaluationMode m, float orientation=0)
Definition Spline.h:176
void set_length(index_type i, length_type length)
Definition Spline.h:213
length_type length() const
Definition Spline.h:203
void evaluate_derivative(float t, Vector3 &hermite) const
Definition SplineImpl.h:28
void init_cyclic_spline(const Vector3 *controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation=0)
Definition Spline.h:177
void evaluate_percent(float t, Vector3 &c) const
Definition SplineImpl.h:20
std::string ToString() const
Definition Unit.h:769
uint32 computeDuration(float length, float velocity)
float computeFallTime(float path_length, bool isSafeFall)
uint32 SecToMS(float sec)
float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity=0.0f)
float MSToSec(uint32 ms)
CommonInitializer(float _velocity)
int32 operator()(Spline< int32 > &s, int32 i)
FallInitializer(float _start_elevation)
int32 operator()(Spline< int32 > &s, int32 i)
bool Validate(Unit *unit) const
============================================================================================
MoveSplineInitArgs(size_t path_capacity=16)
struct Movement::FacingInfo::@263 f