mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-29 00:23:48 +00:00
First Commit
For Azeroth!
This commit is contained in:
318
src/server/game/Movement/Spline/MoveSpline.cpp
Normal file
318
src/server/game/Movement/Spline/MoveSpline.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "MoveSpline.h"
|
||||
#include <sstream>
|
||||
#include "Log.h"
|
||||
#include "Creature.h"
|
||||
|
||||
namespace Movement{
|
||||
|
||||
Location MoveSpline::ComputePosition() const
|
||||
{
|
||||
ASSERT(Initialized());
|
||||
|
||||
float u = 1.f;
|
||||
int32 seg_time = spline.length(point_Idx, point_Idx+1);
|
||||
if (seg_time > 0)
|
||||
u = (time_passed - spline.length(point_Idx)) / (float)seg_time;
|
||||
Location c;
|
||||
c.orientation = initialOrientation;
|
||||
spline.evaluate_percent(point_Idx, u, c);
|
||||
|
||||
if (splineflags.animation)
|
||||
;// MoveSplineFlag::Animation disables falling or parabolic movement
|
||||
else if (splineflags.parabolic)
|
||||
computeParabolicElevation(c.z);
|
||||
else if (splineflags.falling)
|
||||
computeFallElevation(c.z);
|
||||
|
||||
if (splineflags.done && splineflags.isFacing())
|
||||
{
|
||||
if (splineflags.final_angle)
|
||||
c.orientation = facing.angle;
|
||||
else if (splineflags.final_point)
|
||||
c.orientation = atan2(facing.f.y - c.y, facing.f.x - c.x);
|
||||
//nothing to do for MoveSplineFlag::Final_Target flag
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed | MoveSplineFlag::Falling))
|
||||
{
|
||||
Vector3 hermite;
|
||||
spline.evaluate_derivative(point_Idx, u, hermite);
|
||||
c.orientation = atan2(hermite.y, hermite.x);
|
||||
}
|
||||
|
||||
if (splineflags.orientationInversed)
|
||||
c.orientation = -c.orientation;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void MoveSpline::computeParabolicElevation(float& el) const
|
||||
{
|
||||
if (time_passed > effect_start_time)
|
||||
{
|
||||
float t_passedf = MSToSec(time_passed - effect_start_time);
|
||||
float t_durationf = MSToSec(Duration() - effect_start_time); //client use not modified duration here
|
||||
|
||||
// -a*x*x + bx + c:
|
||||
//(dur * v3->z_acceleration * dt)/2 - (v3->z_acceleration * dt * dt)/2 + Z;
|
||||
el += (t_durationf - t_passedf) * 0.5f * vertical_acceleration * t_passedf;
|
||||
}
|
||||
}
|
||||
|
||||
void MoveSpline::computeFallElevation(float& el) const
|
||||
{
|
||||
float z_now = spline.getPoint(spline.first(), false).z - Movement::computeFallElevation(MSToSec(time_passed), false);
|
||||
float final_z = FinalDestination().z;
|
||||
el = std::max(z_now, final_z);
|
||||
}
|
||||
|
||||
inline uint32 computeDuration(float length, float velocity)
|
||||
{
|
||||
return SecToMS(length / velocity);
|
||||
}
|
||||
|
||||
struct FallInitializer
|
||||
{
|
||||
FallInitializer(float _start_elevation) : start_elevation(_start_elevation) {}
|
||||
float start_elevation;
|
||||
inline int32 operator()(Spline<int32>& s, int32 i)
|
||||
{
|
||||
return Movement::computeFallTime(start_elevation - s.getPoint(i+1, false).z, false) * 1000.f;
|
||||
}
|
||||
};
|
||||
|
||||
enum{
|
||||
minimal_duration = 1
|
||||
};
|
||||
|
||||
struct CommonInitializer
|
||||
{
|
||||
CommonInitializer(float _velocity) : velocityInv(1000.f/_velocity), time(minimal_duration) {}
|
||||
float velocityInv;
|
||||
int32 time;
|
||||
inline int32 operator()(Spline<int32>& s, int32 i)
|
||||
{
|
||||
time += (s.SegLength(i) * velocityInv);
|
||||
return time;
|
||||
}
|
||||
};
|
||||
|
||||
void MoveSpline::init_spline(const MoveSplineInitArgs& args)
|
||||
{
|
||||
const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear, SplineBase::ModeCatmullrom};
|
||||
if (args.flags.cyclic)
|
||||
{
|
||||
uint32 cyclic_point = 0;
|
||||
// MoveSplineFlag::Enter_Cycle support dropped
|
||||
//if (splineflags & SPLINEFLAG_ENTER_CYCLE)
|
||||
//cyclic_point = 1; // shouldn't be modified, came from client
|
||||
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point);
|
||||
}
|
||||
else
|
||||
{
|
||||
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]);
|
||||
}
|
||||
|
||||
// init spline timestamps
|
||||
if (splineflags.falling)
|
||||
{
|
||||
FallInitializer init(spline.getPoint(spline.first(), false).z);
|
||||
spline.initLengths(init);
|
||||
}
|
||||
else
|
||||
{
|
||||
CommonInitializer init(args.velocity);
|
||||
spline.initLengths(init);
|
||||
}
|
||||
|
||||
// TODO: what to do in such cases? problem is in input data (all points are at same coords)
|
||||
if (spline.length() < minimal_duration)
|
||||
{
|
||||
//sLog->outError("MoveSpline::init_spline: zero length spline, wrong input data?"); // ZOMG! temp comment to avoid console spam from transports
|
||||
spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
|
||||
}
|
||||
point_Idx = spline.first();
|
||||
}
|
||||
|
||||
void MoveSpline::Initialize(MoveSplineInitArgs const& args)
|
||||
{
|
||||
splineflags = args.flags;
|
||||
facing = args.facing;
|
||||
m_Id = args.splineId;
|
||||
point_Idx_offset = args.path_Idx_offset;
|
||||
initialOrientation = args.initialOrientation;
|
||||
|
||||
time_passed = 0;
|
||||
vertical_acceleration = 0.f;
|
||||
effect_start_time = 0;
|
||||
|
||||
// Check if its a stop spline
|
||||
if (args.flags.done)
|
||||
{
|
||||
spline.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
init_spline(args);
|
||||
|
||||
// init parabolic / animation
|
||||
// spline initialized, duration known and i able to compute parabolic acceleration
|
||||
if (args.flags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation))
|
||||
{
|
||||
effect_start_time = Duration() * args.time_perc;
|
||||
if (args.flags.parabolic && effect_start_time < Duration())
|
||||
{
|
||||
float f_duration = MSToSec(Duration() - effect_start_time);
|
||||
vertical_acceleration = args.parabolic_amplitude * 8.f / (f_duration * f_duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoveSpline::MoveSpline() : m_Id(0), time_passed(0),
|
||||
vertical_acceleration(0.f), initialOrientation(0.f), effect_start_time(0), point_Idx(0), point_Idx_offset(0),
|
||||
onTransport(false)
|
||||
{
|
||||
splineflags.done = true;
|
||||
}
|
||||
|
||||
/// ============================================================================================
|
||||
|
||||
bool MoveSplineInitArgs::Validate(Unit* unit) const
|
||||
{
|
||||
#define CHECK(exp) \
|
||||
if (!(exp))\
|
||||
{\
|
||||
sLog->outError("MoveSplineInitArgs::Validate: expression '%s' failed for GUID: %u Entry: %u", #exp, unit->GetTypeId() == TYPEID_PLAYER ? unit->GetGUIDLow() : unit->ToCreature()->GetDBTableGUIDLow(), unit->GetEntry());\
|
||||
return false;\
|
||||
}
|
||||
CHECK(path.size() > 1);
|
||||
CHECK(velocity > 0.1f);
|
||||
CHECK(time_perc >= 0.f && time_perc <= 1.f);
|
||||
//CHECK(_checkPathBounds());
|
||||
return true;
|
||||
#undef CHECK
|
||||
}
|
||||
|
||||
// MONSTER_MOVE packet format limitation for not CatmullRom movement:
|
||||
// each vertex offset packed into 11 bytes
|
||||
bool MoveSplineInitArgs::_checkPathBounds() const
|
||||
{
|
||||
if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2)
|
||||
{
|
||||
enum{
|
||||
MAX_OFFSET = (1 << 11) / 2
|
||||
};
|
||||
Vector3 middle = (path.front()+path.back()) / 2;
|
||||
Vector3 offset;
|
||||
for (uint32 i = 1; i < path.size()-1; ++i)
|
||||
{
|
||||
offset = path[i] - middle;
|
||||
if (fabs(offset.x) >= MAX_OFFSET || fabs(offset.y) >= MAX_OFFSET || fabs(offset.z) >= MAX_OFFSET)
|
||||
{
|
||||
sLog->outError("MoveSplineInitArgs::_checkPathBounds check failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ============================================================================================
|
||||
|
||||
MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff)
|
||||
{
|
||||
if (Finalized())
|
||||
{
|
||||
ms_time_diff = 0;
|
||||
return Result_Arrived;
|
||||
}
|
||||
|
||||
UpdateResult result = Result_None;
|
||||
|
||||
int32 minimal_diff = std::min(ms_time_diff, segment_time_elapsed());
|
||||
ASSERT(minimal_diff >= 0);
|
||||
time_passed += minimal_diff;
|
||||
ms_time_diff -= minimal_diff;
|
||||
|
||||
if (time_passed >= next_timestamp())
|
||||
{
|
||||
++point_Idx;
|
||||
if (point_Idx < spline.last())
|
||||
{
|
||||
result = Result_NextSegment;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spline.isCyclic())
|
||||
{
|
||||
point_Idx = spline.first();
|
||||
time_passed = time_passed % Duration();
|
||||
result = Movement::MoveSpline::UpdateResult(Result_NextCycle | Result_JustArrived);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Finalize();
|
||||
ms_time_diff = 0;
|
||||
result = Movement::MoveSpline::UpdateResult(Result_Arrived | Result_JustArrived);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string MoveSpline::ToString() const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "MoveSpline" << std::endl;
|
||||
str << "spline Id: " << GetId() << std::endl;
|
||||
str << "flags: " << splineflags.ToString() << std::endl;
|
||||
if (splineflags.final_angle)
|
||||
str << "facing angle: " << facing.angle;
|
||||
else if (splineflags.final_target)
|
||||
str << "facing target: " << facing.target;
|
||||
else if (splineflags.final_point)
|
||||
str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z;
|
||||
str << std::endl;
|
||||
str << "time passed: " << time_passed << std::endl;
|
||||
str << "total time: " << Duration() << std::endl;
|
||||
str << "spline point Id: " << point_Idx << std::endl;
|
||||
str << "path point Id: " << currentPathIdx() << std::endl;
|
||||
str << spline.ToString();
|
||||
return str.str();
|
||||
}
|
||||
|
||||
void MoveSpline::_Finalize()
|
||||
{
|
||||
splineflags.done = true;
|
||||
point_Idx = spline.last() - 1;
|
||||
time_passed = Duration();
|
||||
}
|
||||
|
||||
int32 MoveSpline::currentPathIdx() const
|
||||
{
|
||||
int32 point = point_Idx_offset + point_Idx - spline.first() + (int)Finalized();
|
||||
if (isCyclic())
|
||||
point = point % (spline.last()-spline.first());
|
||||
return point;
|
||||
}
|
||||
}
|
||||
129
src/server/game/Movement/Spline/MoveSpline.h
Normal file
129
src/server/game/Movement/Spline/MoveSpline.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVEPLINE_H
|
||||
#define TRINITYSERVER_MOVEPLINE_H
|
||||
|
||||
#include "Spline.h"
|
||||
#include "MoveSplineInitArgs.h"
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
struct Location : public Vector3
|
||||
{
|
||||
Location() : orientation(0) {}
|
||||
Location(float x, float y, float z, float o) : Vector3(x, y, z), orientation(o) {}
|
||||
Location(const Vector3& v) : Vector3(v), orientation(0) {}
|
||||
Location(const Vector3& v, float o) : Vector3(v), orientation(o) {}
|
||||
|
||||
float orientation;
|
||||
};
|
||||
|
||||
// MoveSpline represents smooth catmullrom or linear curve and point that moves belong it
|
||||
// curve can be cyclic - in this case movement will be cyclic
|
||||
// point can have vertical acceleration motion componemt(used in fall, parabolic movement)
|
||||
class MoveSpline
|
||||
{
|
||||
public:
|
||||
typedef Spline<int32> MySpline;
|
||||
enum UpdateResult
|
||||
{
|
||||
Result_None = 0x01,
|
||||
Result_Arrived = 0x02,
|
||||
Result_NextCycle = 0x04,
|
||||
Result_NextSegment = 0x08,
|
||||
Result_JustArrived = 0x10,
|
||||
};
|
||||
friend class PacketBuilder;
|
||||
protected:
|
||||
MySpline spline;
|
||||
|
||||
FacingInfo facing;
|
||||
|
||||
uint32 m_Id;
|
||||
|
||||
MoveSplineFlag splineflags;
|
||||
|
||||
int32 time_passed;
|
||||
// currently duration mods are unused, but its _currently_
|
||||
//float duration_mod;
|
||||
//float duration_mod_next;
|
||||
float vertical_acceleration;
|
||||
float initialOrientation;
|
||||
int32 effect_start_time;
|
||||
int32 point_Idx;
|
||||
int32 point_Idx_offset;
|
||||
|
||||
void init_spline(const MoveSplineInitArgs& args);
|
||||
|
||||
protected:
|
||||
const MySpline::ControlArray& getPath(bool visual) const { return spline.getPoints(visual); }
|
||||
void computeParabolicElevation(float& el) const;
|
||||
void computeFallElevation(float& el) const;
|
||||
|
||||
UpdateResult _updateState(int32& ms_time_diff);
|
||||
int32 next_timestamp() const { return spline.length(point_Idx + 1); }
|
||||
int32 segment_time_elapsed() const { return next_timestamp() - time_passed; }
|
||||
|
||||
public:
|
||||
int32 timeElapsed() const { return Duration() - time_passed; } // xinef: moved to public for waypoint movegen
|
||||
int32 timePassed() const { return time_passed; } // xinef: moved to public for waypoint movegen
|
||||
int32 Duration() const { return spline.length(); }
|
||||
MySpline const& _Spline() const { return spline; }
|
||||
int32 _currentSplineIdx() const { return point_Idx; }
|
||||
void _Finalize();
|
||||
void _Interrupt() { splineflags.done = true; }
|
||||
|
||||
public:
|
||||
void Initialize(const MoveSplineInitArgs&);
|
||||
bool Initialized() const { return !spline.empty(); }
|
||||
|
||||
MoveSpline();
|
||||
|
||||
template<class UpdateHandler>
|
||||
void updateState(int32 difftime, UpdateHandler& handler)
|
||||
{
|
||||
ASSERT(Initialized());
|
||||
do
|
||||
handler(_updateState(difftime));
|
||||
while (difftime > 0);
|
||||
}
|
||||
|
||||
void updateState(int32 difftime)
|
||||
{
|
||||
ASSERT(Initialized());
|
||||
do _updateState(difftime);
|
||||
while (difftime > 0);
|
||||
}
|
||||
|
||||
Location ComputePosition() const;
|
||||
|
||||
uint32 GetId() const { return m_Id; }
|
||||
bool Finalized() const { return splineflags.done; }
|
||||
bool isCyclic() const { return splineflags.cyclic; }
|
||||
bool isFalling() const { return splineflags.falling; }
|
||||
bool isWalking() const { return splineflags.walkmode; }
|
||||
Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last(), false) : Vector3(); }
|
||||
Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1, false) : Vector3(); }
|
||||
int32 currentPathIdx() const;
|
||||
|
||||
bool onTransport;
|
||||
std::string ToString() const;
|
||||
};
|
||||
}
|
||||
#endif // TRINITYSERVER_MOVEPLINE_H
|
||||
146
src/server/game/Movement/Spline/MoveSplineFlag.h
Normal file
146
src/server/game/Movement/Spline/MoveSplineFlag.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#define TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#include "MovementTypedefs.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
#if defined( __GNUC__ )
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
class MoveSplineFlag
|
||||
{
|
||||
public:
|
||||
enum eFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
// x00-xFF(first byte) used as animation Ids storage in pair with Animation flag
|
||||
Done = 0x00000100,
|
||||
Falling = 0x00000200, // Affects elevation computation, can't be combined with Parabolic flag
|
||||
No_Spline = 0x00000400,
|
||||
Parabolic = 0x00000800, // Affects elevation computation, can't be combined with Falling flag
|
||||
Walkmode = 0x00001000,
|
||||
Flying = 0x00002000, // Smooth movement(Catmullrom interpolation mode), flying animation
|
||||
OrientationFixed = 0x00004000, // Model orientation fixed
|
||||
Final_Point = 0x00008000,
|
||||
Final_Target = 0x00010000,
|
||||
Final_Angle = 0x00020000,
|
||||
Catmullrom = 0x00040000, // Used Catmullrom interpolation mode
|
||||
Cyclic = 0x00080000, // Movement by cycled spline
|
||||
Enter_Cycle = 0x00100000, // Everytimes appears with cyclic flag in monster move packet, erases first spline vertex after first cycle done
|
||||
Animation = 0x00200000, // Plays animation after some time passed
|
||||
Frozen = 0x00400000, // Will never arrive
|
||||
TransportEnter = 0x00800000,
|
||||
TransportExit = 0x01000000,
|
||||
Unknown7 = 0x02000000,
|
||||
Unknown8 = 0x04000000,
|
||||
OrientationInversed = 0x08000000,
|
||||
Unknown10 = 0x10000000,
|
||||
Unknown11 = 0x20000000,
|
||||
Unknown12 = 0x40000000,
|
||||
Unknown13 = 0x80000000,
|
||||
|
||||
// Masks
|
||||
Mask_Final_Facing = Final_Point | Final_Target | Final_Angle,
|
||||
// animation ids stored here, see AnimType enum, used with Animation flag
|
||||
Mask_Animations = 0xFF,
|
||||
// flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably
|
||||
Mask_No_Monster_Move = Mask_Final_Facing | Mask_Animations | Done,
|
||||
// CatmullRom interpolation mode used
|
||||
Mask_CatmullRom = Flying | Catmullrom,
|
||||
// Unused, not suported flags
|
||||
Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown7|Unknown8|Unknown10|Unknown11|Unknown12|Unknown13
|
||||
};
|
||||
|
||||
inline uint32& raw() { return (uint32&)*this; }
|
||||
inline const uint32& raw() const { return (const uint32&)*this; }
|
||||
|
||||
MoveSplineFlag() { raw() = 0; }
|
||||
MoveSplineFlag(uint32 f) { raw() = f; }
|
||||
MoveSplineFlag(const MoveSplineFlag& f) { raw() = f.raw(); }
|
||||
|
||||
// Constant interface
|
||||
|
||||
bool isSmooth() const { return raw() & Mask_CatmullRom; }
|
||||
bool isLinear() const { return !isSmooth(); }
|
||||
bool isFacing() const { return raw() & Mask_Final_Facing; }
|
||||
|
||||
uint8 getAnimationId() const { return animId; }
|
||||
bool hasAllFlags(uint32 f) const { return (raw() & f) == f; }
|
||||
bool hasFlag(uint32 f) const { return (raw() & f) != 0; }
|
||||
uint32 operator & (uint32 f) const { return (raw() & f); }
|
||||
uint32 operator | (uint32 f) const { return (raw() | f); }
|
||||
std::string ToString() const;
|
||||
|
||||
// Not constant interface
|
||||
|
||||
void operator &= (uint32 f) { raw() &= f; }
|
||||
void operator |= (uint32 f) { raw() |= f; }
|
||||
|
||||
void EnableAnimation(uint8 anim) { raw() = (raw() & ~(Mask_Animations | Falling | Parabolic)) | Animation | anim; }
|
||||
void EnableParabolic() { raw() = (raw() & ~(Mask_Animations | Falling | Animation)) | Parabolic; }
|
||||
void EnableFalling() { raw() = (raw() & ~(Mask_Animations | Parabolic | Flying | Animation)) | Falling; }
|
||||
void EnableFlying() { raw() = (raw() & ~(Falling | Catmullrom)) | Flying; }
|
||||
void EnableCatmullRom() { raw() = (raw() & ~Flying) | Catmullrom; }
|
||||
void EnableFacingPoint() { raw() = (raw() & ~Mask_Final_Facing) | Final_Point; }
|
||||
void EnableFacingAngle() { raw() = (raw() & ~Mask_Final_Facing) | Final_Angle; }
|
||||
void EnableFacingTarget() { raw() = (raw() & ~Mask_Final_Facing) | Final_Target; }
|
||||
void EnableTransportEnter() { raw() = (raw() & ~TransportExit) | TransportEnter; }
|
||||
void EnableTransportExit() { raw() = (raw() & ~TransportEnter) | TransportExit; }
|
||||
|
||||
uint8 animId : 8;
|
||||
bool done : 1;
|
||||
bool falling : 1;
|
||||
bool no_spline : 1;
|
||||
bool parabolic : 1;
|
||||
bool walkmode : 1;
|
||||
bool flying : 1;
|
||||
bool orientationFixed : 1;
|
||||
bool final_point : 1;
|
||||
bool final_target : 1;
|
||||
bool final_angle : 1;
|
||||
bool catmullrom : 1;
|
||||
bool cyclic : 1;
|
||||
bool enter_cycle : 1;
|
||||
bool animation : 1;
|
||||
bool frozen : 1;
|
||||
bool transportEnter : 1;
|
||||
bool transportExit : 1;
|
||||
bool unknown7 : 1;
|
||||
bool unknown8 : 1;
|
||||
bool orientationInversed : 1;
|
||||
bool unknown10 : 1;
|
||||
bool unknown11 : 1;
|
||||
bool unknown12 : 1;
|
||||
bool unknown13 : 1;
|
||||
};
|
||||
#if defined( __GNUC__ )
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
242
src/server/game/Movement/Spline/MoveSplineInit.cpp
Normal file
242
src/server/game/Movement/Spline/MoveSplineInit.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
#include "MovementPacketBuilder.h"
|
||||
#include "Unit.h"
|
||||
#include "Transport.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Opcodes.h"
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
UnitMoveType SelectSpeedType(uint32 moveFlags)
|
||||
{
|
||||
if (moveFlags & MOVEMENTFLAG_FLYING)
|
||||
{
|
||||
if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.flight >= speed_obj.flight_back*/)
|
||||
return MOVE_FLIGHT_BACK;
|
||||
else
|
||||
return MOVE_FLIGHT;
|
||||
}
|
||||
else if (moveFlags & MOVEMENTFLAG_SWIMMING)
|
||||
{
|
||||
if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.swim >= speed_obj.swim_back*/)
|
||||
return MOVE_SWIM_BACK;
|
||||
else
|
||||
return MOVE_SWIM;
|
||||
}
|
||||
else if (moveFlags & MOVEMENTFLAG_WALKING)
|
||||
{
|
||||
//if (speed_obj.run > speed_obj.walk)
|
||||
return MOVE_WALK;
|
||||
}
|
||||
else if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.run >= speed_obj.run_back*/)
|
||||
return MOVE_RUN_BACK;
|
||||
|
||||
// Flying creatures use MOVEMENTFLAG_CAN_FLY or MOVEMENTFLAG_DISABLE_GRAVITY
|
||||
// Run speed is their default flight speed.
|
||||
return MOVE_RUN;
|
||||
}
|
||||
|
||||
int32 MoveSplineInit::Launch()
|
||||
{
|
||||
MoveSpline& move_spline = *unit->movespline;
|
||||
|
||||
bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID();
|
||||
Location real_position;
|
||||
// there is a big chance that current position is unknown if current state is not finalized, need compute it
|
||||
// this also allows CalculatePath spline position and update map position in much greater intervals
|
||||
// Don't compute for transport movement if the unit is in a motion between two transports
|
||||
if (!move_spline.Finalized() && move_spline.onTransport == transport)
|
||||
real_position = move_spline.ComputePosition();
|
||||
else
|
||||
{
|
||||
Position const* pos;
|
||||
if (!transport)
|
||||
pos = unit;
|
||||
else
|
||||
pos = &unit->m_movementInfo.transport.pos;
|
||||
|
||||
real_position.x = pos->GetPositionX();
|
||||
real_position.y = pos->GetPositionY();
|
||||
real_position.z = pos->GetPositionZ();
|
||||
real_position.orientation = unit->GetOrientation();
|
||||
}
|
||||
|
||||
// should i do the things that user should do? - no.
|
||||
if (args.path.empty())
|
||||
return 0;
|
||||
|
||||
// corrent first vertex
|
||||
args.path[0] = real_position;
|
||||
args.initialOrientation = real_position.orientation;
|
||||
move_spline.onTransport = transport;
|
||||
|
||||
uint32 moveFlags = unit->m_movementInfo.GetMovementFlags();
|
||||
moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD);
|
||||
|
||||
if (moveFlags & MOVEMENTFLAG_ROOT)
|
||||
moveFlags &= ~MOVEMENTFLAG_MASK_MOVING;
|
||||
|
||||
if (!args.HasVelocity)
|
||||
{
|
||||
// If spline is initialized with SetWalk method it only means we need to select
|
||||
// walk move speed for it but not add walk flag to unit
|
||||
uint32 moveFlagsForSpeed = moveFlags;
|
||||
if (args.flags.walkmode)
|
||||
moveFlagsForSpeed |= MOVEMENTFLAG_WALKING;
|
||||
else
|
||||
moveFlagsForSpeed &= ~MOVEMENTFLAG_WALKING;
|
||||
|
||||
args.velocity = unit->GetSpeed(SelectSpeedType(moveFlagsForSpeed));
|
||||
}
|
||||
|
||||
if (!args.Validate(unit))
|
||||
return 0;
|
||||
|
||||
unit->m_movementInfo.SetMovementFlags(moveFlags);
|
||||
move_spline.Initialize(args);
|
||||
|
||||
WorldPacket data(SMSG_MONSTER_MOVE, 64);
|
||||
data.append(unit->GetPackGUID());
|
||||
if (transport)
|
||||
{
|
||||
data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT);
|
||||
data.appendPackGUID(unit->GetTransGUID());
|
||||
data << int8(unit->GetTransSeat());
|
||||
}
|
||||
|
||||
Movement::SplineBase::ControlArray* visualPoints = const_cast<Movement::SplineBase::ControlArray*>(move_spline._Spline().allocateVisualPoints());
|
||||
visualPoints->resize(move_spline._Spline().getPointCount());
|
||||
// Xinef: Apply hover in creature movement packet
|
||||
if (unit->IsHovering())
|
||||
std::transform(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin(), HoverMovementTransform(unit->GetHoverHeight()));
|
||||
else
|
||||
std::copy(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin());
|
||||
|
||||
PacketBuilder::WriteMonsterMove(move_spline, data);
|
||||
unit->SendMessageToSet(&data,true);
|
||||
|
||||
return move_spline.Duration();
|
||||
}
|
||||
|
||||
void MoveSplineInit::Stop()
|
||||
{
|
||||
MoveSpline& move_spline = *unit->movespline;
|
||||
|
||||
// No need to stop if we are not moving
|
||||
if (move_spline.Finalized())
|
||||
return;
|
||||
|
||||
bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID();
|
||||
Location loc;
|
||||
if (move_spline.onTransport == transport)
|
||||
loc = move_spline.ComputePosition();
|
||||
else
|
||||
{
|
||||
Position const* pos;
|
||||
if (!transport)
|
||||
pos = unit;
|
||||
else
|
||||
pos = &unit->m_movementInfo.transport.pos;
|
||||
|
||||
loc.x = pos->GetPositionX();
|
||||
loc.y = pos->GetPositionY();
|
||||
loc.z = pos->GetPositionZ();
|
||||
loc.orientation = unit->GetOrientation();
|
||||
}
|
||||
|
||||
args.flags = MoveSplineFlag::Done;
|
||||
unit->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE_ENABLED);
|
||||
move_spline.onTransport = transport;
|
||||
move_spline.Initialize(args);
|
||||
|
||||
WorldPacket data(SMSG_MONSTER_MOVE, 64);
|
||||
data.append(unit->GetPackGUID());
|
||||
if (transport)
|
||||
{
|
||||
data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT);
|
||||
data.appendPackGUID(unit->GetTransGUID());
|
||||
data << int8(unit->GetTransSeat());
|
||||
}
|
||||
|
||||
// Xinef: increase z position in packet
|
||||
loc.z += unit->GetHoverHeight();
|
||||
PacketBuilder::WriteStopMovement(loc, args.splineId, data);
|
||||
unit->SendMessageToSet(&data, true);
|
||||
}
|
||||
MoveSplineInit::MoveSplineInit(Unit* m) : unit(m)
|
||||
{
|
||||
args.splineId = splineIdGen.NewId();
|
||||
args.TransformForTransport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID();
|
||||
// mix existing state into new
|
||||
args.flags.walkmode = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
args.flags.flying = unit->m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY));
|
||||
}
|
||||
|
||||
void MoveSplineInit::SetFacing(const Unit* target)
|
||||
{
|
||||
args.flags.EnableFacingTarget();
|
||||
args.facing.target = target->GetGUID();
|
||||
}
|
||||
|
||||
void MoveSplineInit::SetFacing(float angle)
|
||||
{
|
||||
if (args.TransformForTransport)
|
||||
{
|
||||
if (Unit* vehicle = unit->GetVehicleBase())
|
||||
angle -= vehicle->GetOrientation();
|
||||
else if (Transport* transport = unit->GetTransport())
|
||||
angle -= transport->GetOrientation();
|
||||
}
|
||||
|
||||
args.facing.angle = G3D::wrap(angle, 0.f, (float)G3D::twoPi());
|
||||
args.flags.EnableFacingAngle();
|
||||
}
|
||||
|
||||
void MoveSplineInit::MoveTo(const Vector3& dest, bool generatePath, bool forceDestination)
|
||||
{
|
||||
if (generatePath)
|
||||
{
|
||||
PathGenerator path(unit);
|
||||
bool result = path.CalculatePath(dest.x, dest.y, dest.z, forceDestination);
|
||||
if (result && !(path.GetPathType() & PATHFIND_NOPATH))
|
||||
{
|
||||
MovebyPath(path.GetPath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
args.path_Idx_offset = 0;
|
||||
args.path.resize(2);
|
||||
TransportPathTransform transform(unit, args.TransformForTransport);
|
||||
args.path[1] = transform(dest);
|
||||
}
|
||||
|
||||
Vector3 TransportPathTransform::operator()(Vector3 input)
|
||||
{
|
||||
if (_transformForTransport)
|
||||
if (TransportBase* transport = _owner->GetDirectTransport())
|
||||
transport->CalculatePassengerOffset(input.x, input.y, input.z);
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
214
src/server/game/Movement/Spline/MoveSplineInit.h
Normal file
214
src/server/game/Movement/Spline/MoveSplineInit.h
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEINIT_H
|
||||
#define TRINITYSERVER_MOVESPLINEINIT_H
|
||||
|
||||
#include "MoveSplineInitArgs.h"
|
||||
#include "PathGenerator.h"
|
||||
|
||||
class Unit;
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
// xinef: moved declaration here so it can be accessed out of MoveSplineInit.cpp
|
||||
UnitMoveType SelectSpeedType(uint32 moveFlags);
|
||||
|
||||
enum AnimType
|
||||
{
|
||||
ToGround = 0, // 460 = ToGround, index of AnimationData.dbc
|
||||
FlyToFly = 1, // 461 = FlyToFly?
|
||||
ToFly = 2, // 458 = ToFly
|
||||
FlyToGround = 3 // 463 = FlyToGround
|
||||
};
|
||||
|
||||
// Transforms coordinates from global to transport offsets
|
||||
class TransportPathTransform
|
||||
{
|
||||
public:
|
||||
TransportPathTransform(Unit* owner, bool transformForTransport)
|
||||
: _owner(owner), _transformForTransport(transformForTransport) { }
|
||||
Vector3 operator()(Vector3 input);
|
||||
|
||||
private:
|
||||
Unit* _owner;
|
||||
bool _transformForTransport;
|
||||
};
|
||||
|
||||
// Xinef: transforms z coordinate with hover offset
|
||||
class HoverMovementTransform
|
||||
{
|
||||
public:
|
||||
HoverMovementTransform(float z_offset) : _offset(z_offset) { }
|
||||
Vector3 operator()(Vector3 input)
|
||||
{
|
||||
input.z += _offset;
|
||||
return input;
|
||||
}
|
||||
|
||||
private:
|
||||
float _offset;
|
||||
};
|
||||
|
||||
/* Initializes and launches spline movement
|
||||
*/
|
||||
class MoveSplineInit
|
||||
{
|
||||
public:
|
||||
|
||||
explicit MoveSplineInit(Unit* m);
|
||||
|
||||
/* Final pass of initialization that launches spline movement.
|
||||
*/
|
||||
int32 Launch();
|
||||
|
||||
/* Final pass of initialization that stops movement.
|
||||
*/
|
||||
void Stop();
|
||||
|
||||
/* Adds movement by parabolic trajectory
|
||||
* @param amplitude - the maximum height of parabola, value could be negative and positive
|
||||
* @param start_time - delay between movement starting time and beginning to move by parabolic trajectory
|
||||
* can't be combined with final animation
|
||||
*/
|
||||
void SetParabolic(float amplitude, float start_time);
|
||||
/* Plays animation after movement done
|
||||
* can't be combined with parabolic movement
|
||||
*/
|
||||
void SetAnimation(AnimType anim);
|
||||
|
||||
/* Adds final facing animation
|
||||
* sets unit's facing to specified point/angle after all path done
|
||||
* you can have only one final facing: previous will be overriden
|
||||
*/
|
||||
void SetFacing(float angle);
|
||||
void SetFacing(Vector3 const& point);
|
||||
void SetFacing(const Unit* target);
|
||||
|
||||
/* Initializes movement by path
|
||||
* @param path - array of points, shouldn't be empty
|
||||
* @param pointId - Id of fisrt point of the path. Example: when third path point will be done it will notify that pointId + 3 done
|
||||
*/
|
||||
void MovebyPath(const PointsArray& path, int32 pointId = 0);
|
||||
|
||||
/* Initializes simple A to B motion, A is current unit's position, B is destination
|
||||
*/
|
||||
void MoveTo(const Vector3& destination, bool generatePath = false, bool forceDestination = false);
|
||||
void MoveTo(float x, float y, float z, bool generatePath = false, bool forceDestination = false);
|
||||
|
||||
/* Sets Id of fisrt point of the path. When N-th path point will be done ILisener will notify that pointId + N done
|
||||
* Needed for waypoint movement where path splitten into parts
|
||||
*/
|
||||
void SetFirstPointId(int32 pointId) { args.path_Idx_offset = pointId; }
|
||||
|
||||
/* Enables CatmullRom spline interpolation mode(makes path smooth)
|
||||
* if not enabled linear spline mode will be choosen. Disabled by default
|
||||
*/
|
||||
void SetSmooth();
|
||||
/* Enables CatmullRom spline interpolation mode, enables flying animation. Disabled by default
|
||||
*/
|
||||
void SetFly();
|
||||
/* Enables walk mode. Disabled by default
|
||||
*/
|
||||
void SetWalk(bool enable);
|
||||
/* Makes movement cyclic. Disabled by default
|
||||
*/
|
||||
void SetCyclic();
|
||||
/* Enables falling mode. Disabled by default
|
||||
*/
|
||||
void SetFall();
|
||||
/* Enters transport. Disabled by default
|
||||
*/
|
||||
void SetTransportEnter();
|
||||
/* Exits transport. Disabled by default
|
||||
*/
|
||||
void SetTransportExit();
|
||||
/* Inverses unit model orientation. Disabled by default
|
||||
*/
|
||||
void SetOrientationInversed();
|
||||
/* Fixes unit's model rotation. Disabled by default
|
||||
*/
|
||||
void SetOrientationFixed(bool enable);
|
||||
|
||||
/* Sets the velocity (in case you want to have custom movement velocity)
|
||||
* if no set, speed will be selected based on unit's speeds and current movement mode
|
||||
* Has no effect if falling mode enabled
|
||||
* velocity shouldn't be negative
|
||||
*/
|
||||
void SetVelocity(float velocity);
|
||||
|
||||
PointsArray& Path() { return args.path; }
|
||||
|
||||
/* Disables transport coordinate transformations for cases where raw offsets are available
|
||||
*/
|
||||
void DisableTransportPathTransformations();
|
||||
protected:
|
||||
|
||||
MoveSplineInitArgs args;
|
||||
Unit* unit;
|
||||
};
|
||||
|
||||
inline void MoveSplineInit::SetFly() { args.flags.EnableFlying(); }
|
||||
inline void MoveSplineInit::SetWalk(bool enable) { args.flags.walkmode = enable; }
|
||||
inline void MoveSplineInit::SetSmooth() { args.flags.EnableCatmullRom(); }
|
||||
inline void MoveSplineInit::SetCyclic() { args.flags.cyclic = true; }
|
||||
inline void MoveSplineInit::SetFall() { args.flags.EnableFalling(); }
|
||||
inline void MoveSplineInit::SetVelocity(float vel) { args.velocity = vel; args.HasVelocity = true; }
|
||||
inline void MoveSplineInit::SetOrientationInversed() { args.flags.orientationInversed = true;}
|
||||
inline void MoveSplineInit::SetTransportEnter() { args.flags.EnableTransportEnter(); }
|
||||
inline void MoveSplineInit::SetTransportExit() { args.flags.EnableTransportExit(); }
|
||||
inline void MoveSplineInit::SetOrientationFixed(bool enable) { args.flags.orientationFixed = enable; }
|
||||
|
||||
inline void MoveSplineInit::MovebyPath(const PointsArray& controls, int32 path_offset)
|
||||
{
|
||||
args.path_Idx_offset = path_offset;
|
||||
args.path.resize(controls.size());
|
||||
std::transform(controls.begin(), controls.end(), args.path.begin(), TransportPathTransform(unit, args.TransformForTransport));
|
||||
}
|
||||
|
||||
inline void MoveSplineInit::MoveTo(float x, float y, float z, bool generatePath, bool forceDestination)
|
||||
{
|
||||
MoveTo(G3D::Vector3(x, y, z), generatePath, forceDestination);
|
||||
}
|
||||
|
||||
inline void MoveSplineInit::SetParabolic(float amplitude, float time_shift)
|
||||
{
|
||||
args.time_perc = time_shift;
|
||||
args.parabolic_amplitude = amplitude;
|
||||
args.flags.EnableParabolic();
|
||||
}
|
||||
|
||||
inline void MoveSplineInit::SetAnimation(AnimType anim)
|
||||
{
|
||||
args.time_perc = 0.f;
|
||||
args.flags.EnableAnimation((uint8)anim);
|
||||
}
|
||||
|
||||
inline void MoveSplineInit::SetFacing(Vector3 const& spot)
|
||||
{
|
||||
TransportPathTransform transform(unit, args.TransformForTransport);
|
||||
Vector3 finalSpot = transform(spot);
|
||||
args.facing.f.x = finalSpot.x;
|
||||
args.facing.f.y = finalSpot.y;
|
||||
args.facing.f.z = finalSpot.z;
|
||||
args.flags.EnableFacingPoint();
|
||||
}
|
||||
|
||||
inline void MoveSplineInit::DisableTransportPathTransformations() { args.TransformForTransport = false; }
|
||||
}
|
||||
#endif // TRINITYSERVER_MOVESPLINEINIT_H
|
||||
73
src/server/game/Movement/Spline/MoveSplineInitArgs.h
Normal file
73
src/server/game/Movement/Spline/MoveSplineInitArgs.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
#define TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
|
||||
#include "MoveSplineFlag.h"
|
||||
#include <G3D/Vector3.h>
|
||||
|
||||
class Unit;
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
typedef std::vector<Vector3> PointsArray;
|
||||
|
||||
union FacingInfo
|
||||
{
|
||||
struct {
|
||||
float x, y, z;
|
||||
} f;
|
||||
uint64 target;
|
||||
float angle;
|
||||
|
||||
FacingInfo(float o) : angle(o) {}
|
||||
FacingInfo(uint64 t) : target(t) {}
|
||||
FacingInfo() {}
|
||||
};
|
||||
|
||||
struct MoveSplineInitArgs
|
||||
{
|
||||
MoveSplineInitArgs(size_t path_capacity = 16) : path_Idx_offset(0), velocity(0.f),
|
||||
parabolic_amplitude(0.f), time_perc(0.f), splineId(0), initialOrientation(0.f),
|
||||
HasVelocity(false), TransformForTransport(true)
|
||||
{
|
||||
path.reserve(path_capacity);
|
||||
}
|
||||
|
||||
PointsArray path;
|
||||
FacingInfo facing;
|
||||
MoveSplineFlag flags;
|
||||
int32 path_Idx_offset;
|
||||
float velocity;
|
||||
float parabolic_amplitude;
|
||||
float time_perc;
|
||||
uint32 splineId;
|
||||
float initialOrientation;
|
||||
bool HasVelocity;
|
||||
bool TransformForTransport;
|
||||
|
||||
/** Returns true to show that the arguments were configured correctly and MoveSpline initialization will succeed. */
|
||||
bool Validate(Unit* unit) const;
|
||||
|
||||
private:
|
||||
bool _checkPathBounds() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
201
src/server/game/Movement/Spline/MovementPacketBuilder.cpp
Normal file
201
src/server/game/Movement/Spline/MovementPacketBuilder.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "MovementPacketBuilder.h"
|
||||
#include "MoveSpline.h"
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
inline void operator << (ByteBuffer& b, const Vector3& v)
|
||||
{
|
||||
b << v.x << v.y << v.z;
|
||||
}
|
||||
|
||||
inline void operator >> (ByteBuffer& b, Vector3& v)
|
||||
{
|
||||
b >> v.x >> v.y >> v.z;
|
||||
}
|
||||
|
||||
enum MonsterMoveType
|
||||
{
|
||||
MonsterMoveNormal = 0,
|
||||
MonsterMoveStop = 1,
|
||||
MonsterMoveFacingSpot = 2,
|
||||
MonsterMoveFacingTarget = 3,
|
||||
MonsterMoveFacingAngle = 4
|
||||
};
|
||||
|
||||
void PacketBuilder::WriteCommonMonsterMovePart(const MoveSpline& move_spline, ByteBuffer& data)
|
||||
{
|
||||
MoveSplineFlag splineflags = move_spline.splineflags;
|
||||
|
||||
data << uint8(0); // sets/unsets MOVEMENTFLAG2_UNK7 (0x40)
|
||||
data << move_spline.spline.getPoint(move_spline.spline.first(), true);
|
||||
data << move_spline.GetId();
|
||||
|
||||
switch (splineflags & MoveSplineFlag::Mask_Final_Facing)
|
||||
{
|
||||
case MoveSplineFlag::Final_Target:
|
||||
data << uint8(MonsterMoveFacingTarget);
|
||||
data << move_spline.facing.target;
|
||||
break;
|
||||
case MoveSplineFlag::Final_Angle:
|
||||
data << uint8(MonsterMoveFacingAngle);
|
||||
data << move_spline.facing.angle;
|
||||
break;
|
||||
case MoveSplineFlag::Final_Point:
|
||||
data << uint8(MonsterMoveFacingSpot);
|
||||
data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
|
||||
break;
|
||||
default:
|
||||
data << uint8(MonsterMoveNormal);
|
||||
break;
|
||||
}
|
||||
|
||||
// add fake Enter_Cycle flag - needed for client-side cyclic movement (client will erase first spline vertex after first cycle done)
|
||||
// Xinef: this flag breaks cycle for ground movement, client teleports npc between last and first point instead of using smooth movement
|
||||
if (splineflags & MoveSplineFlag::Flying)
|
||||
splineflags.enter_cycle = move_spline.isCyclic();
|
||||
data << uint32(splineflags & uint32(~MoveSplineFlag::Mask_No_Monster_Move));
|
||||
|
||||
if (splineflags.animation)
|
||||
{
|
||||
data << splineflags.getAnimationId();
|
||||
data << move_spline.effect_start_time;
|
||||
}
|
||||
|
||||
data << move_spline.Duration();
|
||||
|
||||
if (splineflags.parabolic)
|
||||
{
|
||||
data << move_spline.vertical_acceleration;
|
||||
data << move_spline.effect_start_time;
|
||||
}
|
||||
}
|
||||
|
||||
void PacketBuilder::WriteStopMovement(Vector3 const& pos, uint32 splineId, ByteBuffer& data)
|
||||
{
|
||||
data << uint8(0); // sets/unsets MOVEMENTFLAG2_UNK7 (0x40)
|
||||
data << pos;
|
||||
data << splineId;
|
||||
data << uint8(MonsterMoveStop);
|
||||
}
|
||||
|
||||
void WriteLinearPath(const Spline<int32>& spline, ByteBuffer& data)
|
||||
{
|
||||
uint32 last_idx = spline.getPointCount() - 3;
|
||||
const Vector3 * real_path = &spline.getPoint(1, true);
|
||||
|
||||
data << last_idx;
|
||||
data << real_path[last_idx]; // destination
|
||||
if (last_idx > 1)
|
||||
{
|
||||
Vector3 middle = (real_path[0] + real_path[last_idx]) / 2.f;
|
||||
Vector3 offset;
|
||||
// first and last points already appended
|
||||
for (uint32 i = 1; i < last_idx; ++i)
|
||||
{
|
||||
offset = middle - real_path[i];
|
||||
data.appendPackXYZ(offset.x, offset.y, offset.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteCatmullRomPath(const Spline<int32>& spline, ByteBuffer& data)
|
||||
{
|
||||
uint32 count = spline.getPointCount() - 3;
|
||||
data << count;
|
||||
data.append<Vector3>(&spline.getPoint(2, true), count);
|
||||
}
|
||||
|
||||
void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data, bool flying)
|
||||
{
|
||||
uint32 count = spline.getPointCount() - 3;
|
||||
data << uint32(count+1);
|
||||
if (flying)
|
||||
{
|
||||
data << spline.getPoint(1, true); // fake point, client will erase it from the spline after first cycle done
|
||||
data.append<Vector3>(&spline.getPoint(2, true), count);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.append<Vector3>(&spline.getPoint(2, true), count);
|
||||
data << Vector3::zero(); //Xinef: fake point
|
||||
}
|
||||
}
|
||||
|
||||
void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, ByteBuffer& data)
|
||||
{
|
||||
WriteCommonMonsterMovePart(move_spline, data);
|
||||
|
||||
const Spline<int32>& spline = move_spline.spline;
|
||||
MoveSplineFlag splineflags = move_spline.splineflags;
|
||||
if (splineflags & MoveSplineFlag::Mask_CatmullRom)
|
||||
{
|
||||
if (splineflags.cyclic)
|
||||
WriteCatmullRomCyclicPath(spline, data, splineflags & MoveSplineFlag::Flying);
|
||||
else
|
||||
WriteCatmullRomPath(spline, data);
|
||||
}
|
||||
else
|
||||
WriteLinearPath(spline, data);
|
||||
}
|
||||
|
||||
void PacketBuilder::WriteCreate(const MoveSpline& move_spline, ByteBuffer& data)
|
||||
{
|
||||
//WriteClientStatus(mov, data);
|
||||
//data.append<float>(&mov.m_float_values[SpeedWalk], SpeedMaxCount);
|
||||
//if (mov.SplineEnabled())
|
||||
{
|
||||
MoveSplineFlag const& splineFlags = move_spline.splineflags;
|
||||
|
||||
data << splineFlags.raw();
|
||||
|
||||
if (splineFlags.final_angle)
|
||||
{
|
||||
data << move_spline.facing.angle;
|
||||
}
|
||||
else if (splineFlags.final_target)
|
||||
{
|
||||
data << move_spline.facing.target;
|
||||
}
|
||||
else if (splineFlags.final_point)
|
||||
{
|
||||
data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
|
||||
}
|
||||
|
||||
data << move_spline.timePassed();
|
||||
data << move_spline.Duration();
|
||||
data << move_spline.GetId();
|
||||
|
||||
data << float(1.f); // splineInfo.duration_mod; added in 3.1
|
||||
data << float(1.f); // splineInfo.duration_mod_next; added in 3.1
|
||||
|
||||
data << move_spline.vertical_acceleration; // added in 3.1
|
||||
data << move_spline.effect_start_time; // added in 3.1
|
||||
|
||||
uint32 nodes = move_spline.getPath(true).size();
|
||||
data << nodes;
|
||||
data.append<Vector3>(&move_spline.getPath(true)[0], nodes);
|
||||
data << uint8(move_spline.spline.mode()); // added in 3.1
|
||||
data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination());
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/server/game/Movement/Spline/MovementPacketBuilder.h
Normal file
46
src/server/game/Movement/Spline/MovementPacketBuilder.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_PACKET_BUILDER_H
|
||||
#define TRINITYSERVER_PACKET_BUILDER_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
class ByteBuffer;
|
||||
namespace G3D
|
||||
{
|
||||
class Vector3;
|
||||
}
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
using G3D::Vector3;
|
||||
|
||||
class MoveSpline;
|
||||
class PacketBuilder
|
||||
{
|
||||
static void WriteCommonMonsterMovePart(const MoveSpline& mov, ByteBuffer& data);
|
||||
public:
|
||||
|
||||
static void WriteMonsterMove(const MoveSpline& mov, ByteBuffer& data);
|
||||
static void WriteStopMovement(Vector3 const& loc, uint32 splineId, ByteBuffer& data);
|
||||
static void WriteCreate(const MoveSpline& mov, ByteBuffer& data);
|
||||
};
|
||||
}
|
||||
#endif // TRINITYSERVER_PACKET_BUILDER_H
|
||||
84
src/server/game/Movement/Spline/MovementTypedefs.h
Normal file
84
src/server/game/Movement/Spline/MovementTypedefs.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_TYPEDEFS_H
|
||||
#define TRINITYSERVER_TYPEDEFS_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace G3D
|
||||
{
|
||||
class Vector2;
|
||||
class Vector3;
|
||||
class Vector4;
|
||||
}
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
using G3D::Vector2;
|
||||
using G3D::Vector3;
|
||||
using G3D::Vector4;
|
||||
|
||||
inline uint32 SecToMS(float sec)
|
||||
{
|
||||
return static_cast<uint32>(sec * 1000.f);
|
||||
}
|
||||
|
||||
inline float MSToSec(uint32 ms)
|
||||
{
|
||||
return ms / 1000.f;
|
||||
}
|
||||
|
||||
float computeFallTime(float path_length, bool isSafeFall);
|
||||
float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity = 0.0f);
|
||||
|
||||
#ifndef static_assert
|
||||
#define CONCAT(x, y) CONCAT1 (x, y)
|
||||
#define CONCAT1(x, y) x##y
|
||||
#define static_assert(expr, msg) typedef char CONCAT(static_assert_failed_at_line_, __LINE__) [(expr) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
template<class T, T limit>
|
||||
class counter
|
||||
{
|
||||
public:
|
||||
counter() { init(); }
|
||||
|
||||
void Increase()
|
||||
{
|
||||
if (m_counter == limit)
|
||||
init();
|
||||
else
|
||||
++m_counter;
|
||||
}
|
||||
|
||||
T NewId() { Increase(); return m_counter; }
|
||||
T getCurrent() const { return m_counter; }
|
||||
|
||||
private:
|
||||
void init() { m_counter = 0; }
|
||||
T m_counter;
|
||||
};
|
||||
|
||||
typedef counter<uint32, 0xFFFFFFFF> UInt32Counter;
|
||||
|
||||
extern double gravity;
|
||||
extern UInt32Counter splineIdGen;
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_TYPEDEFS_H
|
||||
195
src/server/game/Movement/Spline/MovementUtil.cpp
Normal file
195
src/server/game/Movement/Spline/MovementUtil.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "MoveSplineFlag.h"
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
double gravity = 19.29110527038574;
|
||||
UInt32Counter splineIdGen;
|
||||
|
||||
/// Velocity bounds that makes fall speed limited
|
||||
float terminalVelocity = 60.148003f;
|
||||
float terminalSafefallVelocity = 7.0f;
|
||||
|
||||
const float terminal_length = float(terminalVelocity * terminalVelocity) / (2.0f * gravity);
|
||||
const float terminal_safeFall_length = (terminalSafefallVelocity * terminalSafefallVelocity) / (2.0f * gravity);
|
||||
const float terminal_fallTime = float(terminalVelocity / gravity); // the time that needed to reach terminalVelocity
|
||||
const float terminal_safeFall_fallTime = float(terminalSafefallVelocity / gravity); // the time that needed to reach terminalVelocity with safefall
|
||||
|
||||
float computeFallTime(float path_length, bool isSafeFall)
|
||||
{
|
||||
if (path_length < 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
float time;
|
||||
if (isSafeFall)
|
||||
{
|
||||
if (path_length >= terminal_safeFall_length)
|
||||
time = (path_length - terminal_safeFall_length) / terminalSafefallVelocity + terminal_safeFall_fallTime;
|
||||
else
|
||||
time = sqrtf(2.0f * path_length / gravity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (path_length >= terminal_length)
|
||||
time = (path_length - terminal_length) / terminalVelocity + terminal_fallTime;
|
||||
else
|
||||
time = sqrtf(2.0f * path_length / gravity);
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity /*= 0.0f*/)
|
||||
{
|
||||
float termVel;
|
||||
float result;
|
||||
|
||||
if (isSafeFall)
|
||||
termVel = terminalSafefallVelocity;
|
||||
else
|
||||
termVel = terminalVelocity;
|
||||
|
||||
if (start_velocity > termVel)
|
||||
start_velocity = termVel;
|
||||
|
||||
float terminal_time = (isSafeFall ? terminal_safeFall_fallTime : terminal_fallTime) - start_velocity / gravity; // the time that needed to reach terminalVelocity
|
||||
|
||||
if (t_passed > terminal_time)
|
||||
{
|
||||
result = termVel * (t_passed - terminal_time) +
|
||||
start_velocity * terminal_time +
|
||||
gravity * terminal_time * terminal_time*0.5f;
|
||||
}
|
||||
else
|
||||
result = t_passed * (start_velocity + t_passed * gravity * 0.5f);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
char const* g_MovementFlag_names[] =
|
||||
{
|
||||
STR(Forward ), // 0x00000001,
|
||||
STR(Backward ), // 0x00000002,
|
||||
STR(Strafe_Left ), // 0x00000004,
|
||||
STR(Strafe_Right ), // 0x00000008,
|
||||
STR(Turn_Left ), // 0x00000010,
|
||||
STR(Turn_Right ), // 0x00000020,
|
||||
STR(Pitch_Up ), // 0x00000040,
|
||||
STR(Pitch_Down ), // 0x00000080,
|
||||
|
||||
STR(Walk ), // 0x00000100, // Walking
|
||||
STR(Ontransport ), // 0x00000200,
|
||||
STR(Levitation ), // 0x00000400,
|
||||
STR(Root ), // 0x00000800,
|
||||
STR(Falling ), // 0x00001000,
|
||||
STR(Fallingfar ), // 0x00002000,
|
||||
STR(Pendingstop ), // 0x00004000,
|
||||
STR(PendingSTRafestop ), // 0x00008000,
|
||||
STR(Pendingforward ), // 0x00010000,
|
||||
STR(Pendingbackward ), // 0x00020000,
|
||||
STR(PendingSTRafeleft ), // 0x00040000,
|
||||
STR(PendingSTRaferight ), // 0x00080000,
|
||||
STR(Pendingroot ), // 0x00100000,
|
||||
STR(Swimming ), // 0x00200000, // Appears With Fly Flag Also
|
||||
STR(Ascending ), // 0x00400000, // Swim Up Also
|
||||
STR(Descending ), // 0x00800000, // Swim Down Also
|
||||
STR(Can_Fly ), // 0x01000000, // Can Fly In 3.3?
|
||||
STR(Flying ), // 0x02000000, // Actual Flying Mode
|
||||
STR(Spline_Elevation ), // 0x04000000, // Used For Flight Paths
|
||||
STR(Spline_Enabled ), // 0x08000000, // Used For Flight Paths
|
||||
STR(Waterwalking ), // 0x10000000, // Prevent Unit From Falling Through Water
|
||||
STR(Safe_Fall ), // 0x20000000, // Active Rogue Safe Fall Spell (Passive)
|
||||
STR(Hover ), // 0x40000000
|
||||
STR(Unknown13 ), // 0x80000000
|
||||
STR(Unk1 ),
|
||||
STR(Unk2 ),
|
||||
STR(Unk3 ),
|
||||
STR(Fullspeedturning ),
|
||||
STR(Fullspeedpitching ),
|
||||
STR(Allow_Pitching ),
|
||||
STR(Unk4 ),
|
||||
STR(Unk5 ),
|
||||
STR(Unk6 ),
|
||||
STR(Unk7 ),
|
||||
STR(Interp_Move ),
|
||||
STR(Interp_Turning ),
|
||||
STR(Interp_Pitching ),
|
||||
STR(Unk8 ),
|
||||
STR(Unk9 ),
|
||||
STR(Unk10 ),
|
||||
};
|
||||
|
||||
char const* g_SplineFlag_names[32] =
|
||||
{
|
||||
STR(AnimBit1 ), // 0x00000001,
|
||||
STR(AnimBit2 ), // 0x00000002,
|
||||
STR(AnimBit3 ), // 0x00000004,
|
||||
STR(AnimBit4 ), // 0x00000008,
|
||||
STR(AnimBit5 ), // 0x00000010,
|
||||
STR(AnimBit6 ), // 0x00000020,
|
||||
STR(AnimBit7 ), // 0x00000040,
|
||||
STR(AnimBit8 ), // 0x00000080,
|
||||
STR(Done ), // 0x00000100,
|
||||
STR(Falling ), // 0x00000200, // Not Compartible With Trajectory Movement
|
||||
STR(No_Spline ), // 0x00000400,
|
||||
STR(Trajectory ), // 0x00000800, // Not Compartible With Fall Movement
|
||||
STR(Walkmode ), // 0x00001000,
|
||||
STR(Flying ), // 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation
|
||||
STR(Knockback ), // 0x00004000, // Model Orientation Fixed
|
||||
STR(Final_Point ), // 0x00008000,
|
||||
STR(Final_Target ), // 0x00010000,
|
||||
STR(Final_Angle ), // 0x00020000,
|
||||
STR(Catmullrom ), // 0x00040000, // Used Catmullrom Interpolation Mode
|
||||
STR(Cyclic ), // 0x00080000, // Movement By Cycled Spline
|
||||
STR(Enter_Cycle ), // 0x00100000, // Everytime Appears With Cyclic Flag In Monster Move Packet
|
||||
STR(Animation ), // 0x00200000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement
|
||||
STR(Unknown4 ), // 0x00400000, // Disables Movement By Path
|
||||
STR(Unknown5 ), // 0x00800000,
|
||||
STR(Unknown6 ), // 0x01000000,
|
||||
STR(Unknown7 ), // 0x02000000,
|
||||
STR(Unknown8 ), // 0x04000000,
|
||||
STR(OrientationInversed ), // 0x08000000, // Appears With Runmode Flag, Nodes ), // 1, Handles Orientation
|
||||
STR(Unknown10 ), // 0x10000000,
|
||||
STR(Unknown11 ), // 0x20000000,
|
||||
STR(Unknown12 ), // 0x40000000,
|
||||
STR(Unknown13 ), // 0x80000000,
|
||||
};
|
||||
|
||||
template<class Flags, int N>
|
||||
void print_flags(Flags t, char const* (&names)[N], std::string& str)
|
||||
{
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
if ((t & Flags(1 << i)) && names[i] != NULL)
|
||||
str.append(" ").append(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string MoveSplineFlag::ToString() const
|
||||
{
|
||||
std::string str;
|
||||
print_flags(raw(), g_SplineFlag_names, str);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
306
src/server/game/Movement/Spline/Spline.cpp
Normal file
306
src/server/game/Movement/Spline/Spline.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Spline.h"
|
||||
#include <sstream>
|
||||
#include <G3D/Matrix4.h>
|
||||
|
||||
namespace Movement{
|
||||
|
||||
SplineBase::EvaluationMethtod SplineBase::evaluators[SplineBase::ModesEnd] =
|
||||
{
|
||||
&SplineBase::EvaluateLinear,
|
||||
&SplineBase::EvaluateCatmullRom,
|
||||
&SplineBase::EvaluateBezier3,
|
||||
(EvaluationMethtod)&SplineBase::UninitializedSpline,
|
||||
};
|
||||
|
||||
SplineBase::EvaluationMethtod SplineBase::derivative_evaluators[SplineBase::ModesEnd] =
|
||||
{
|
||||
&SplineBase::EvaluateDerivativeLinear,
|
||||
&SplineBase::EvaluateDerivativeCatmullRom,
|
||||
&SplineBase::EvaluateDerivativeBezier3,
|
||||
(EvaluationMethtod)&SplineBase::UninitializedSpline,
|
||||
};
|
||||
|
||||
SplineBase::SegLenghtMethtod SplineBase::seglengths[SplineBase::ModesEnd] =
|
||||
{
|
||||
&SplineBase::SegLengthLinear,
|
||||
&SplineBase::SegLengthCatmullRom,
|
||||
&SplineBase::SegLengthBezier3,
|
||||
(SegLenghtMethtod)&SplineBase::UninitializedSpline,
|
||||
};
|
||||
|
||||
SplineBase::InitMethtod SplineBase::initializers[SplineBase::ModesEnd] =
|
||||
{
|
||||
//&SplineBase::InitLinear,
|
||||
&SplineBase::InitCatmullRom, // we should use catmullrom initializer even for linear mode! (client's internal structure limitation)
|
||||
&SplineBase::InitCatmullRom,
|
||||
&SplineBase::InitBezier3,
|
||||
(InitMethtod)&SplineBase::UninitializedSpline,
|
||||
};
|
||||
|
||||
///////////
|
||||
|
||||
using G3D::Matrix4;
|
||||
static const Matrix4 s_catmullRomCoeffs(
|
||||
-0.5f, 1.5f, -1.5f, 0.5f,
|
||||
1.f, -2.5f, 2.f, -0.5f,
|
||||
-0.5f, 0.f, 0.5f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f);
|
||||
|
||||
static const Matrix4 s_Bezier3Coeffs(
|
||||
-1.f, 3.f, -3.f, 1.f,
|
||||
3.f, -6.f, 3.f, 0.f,
|
||||
-3.f, 3.f, 0.f, 0.f,
|
||||
1.f, 0.f, 0.f, 0.f);
|
||||
|
||||
/* classic view:
|
||||
inline void C_Evaluate(const Vector3 *vertice, float t, const float (&matrix)[4][4], Vector3 &position)
|
||||
{
|
||||
Vector3 tvec(t*t*t, t*t, t);
|
||||
int i = 0;
|
||||
double c;
|
||||
double x = 0, y = 0, z = 0;
|
||||
while ( i < 4 )
|
||||
{
|
||||
c = matrix[0][i]*tvec.x + matrix[1][i]*tvec.y + matrix[2][i]*tvec.z + matrix[3][i];
|
||||
|
||||
x += c * vertice->x;
|
||||
y += c * vertice->y;
|
||||
z += c * vertice->z;
|
||||
|
||||
++i;
|
||||
++vertice;
|
||||
}
|
||||
|
||||
position.x = x;
|
||||
position.y = y;
|
||||
position.z = z;
|
||||
}*/
|
||||
|
||||
inline void C_Evaluate(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result)
|
||||
{
|
||||
Vector4 tvec(t*t*t, t*t, t, 1.f);
|
||||
Vector4 weights(tvec * matr);
|
||||
|
||||
result = vertice[0] * weights[0] + vertice[1] * weights[1]
|
||||
+ vertice[2] * weights[2] + vertice[3] * weights[3];
|
||||
}
|
||||
|
||||
inline void C_Evaluate_Derivative(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result)
|
||||
{
|
||||
Vector4 tvec(3.f*t*t, 2.f*t, 1.f, 0.f);
|
||||
Vector4 weights(tvec * matr);
|
||||
|
||||
result = vertice[0] * weights[0] + vertice[1] * weights[1]
|
||||
+ vertice[2] * weights[2] + vertice[3] * weights[3];
|
||||
}
|
||||
|
||||
void SplineBase::EvaluateLinear(index_type index, float u, Vector3& result) const
|
||||
{
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
result = points[index] + (points[index+1] - points[index]) * u;
|
||||
}
|
||||
|
||||
void SplineBase::EvaluateCatmullRom( index_type index, float t, Vector3& result) const
|
||||
{
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
C_Evaluate(&points[index - 1], t, s_catmullRomCoeffs, result);
|
||||
}
|
||||
|
||||
void SplineBase::EvaluateBezier3(index_type index, float t, Vector3& result) const
|
||||
{
|
||||
index *= 3u;
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
C_Evaluate(&points[index], t, s_Bezier3Coeffs, result);
|
||||
}
|
||||
|
||||
void SplineBase::EvaluateDerivativeLinear(index_type index, float, Vector3& result) const
|
||||
{
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
result = points[index+1] - points[index];
|
||||
}
|
||||
|
||||
void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const
|
||||
{
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
C_Evaluate_Derivative(&points[index - 1], t, s_catmullRomCoeffs, result);
|
||||
}
|
||||
|
||||
void SplineBase::EvaluateDerivativeBezier3(index_type index, float t, Vector3& result) const
|
||||
{
|
||||
index *= 3u;
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result);
|
||||
}
|
||||
|
||||
float SplineBase::SegLengthLinear(index_type index) const
|
||||
{
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
return (points[index] - points[index+1]).length();
|
||||
}
|
||||
|
||||
float SplineBase::SegLengthCatmullRom(index_type index) const
|
||||
{
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
|
||||
Vector3 curPos, nextPos;
|
||||
const Vector3 * p = &points[index - 1];
|
||||
curPos = nextPos = p[1];
|
||||
|
||||
index_type i = 1;
|
||||
double length = 0;
|
||||
while (i <= STEPS_PER_SEGMENT)
|
||||
{
|
||||
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_catmullRomCoeffs, nextPos);
|
||||
length += (nextPos - curPos).length();
|
||||
curPos = nextPos;
|
||||
++i;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
float SplineBase::SegLengthBezier3(index_type index) const
|
||||
{
|
||||
index *= 3u;
|
||||
ASSERT(index >= index_lo && index < index_hi);
|
||||
|
||||
Vector3 curPos, nextPos;
|
||||
const Vector3 * p = &points[index];
|
||||
|
||||
C_Evaluate(p, 0.f, s_Bezier3Coeffs, nextPos);
|
||||
curPos = nextPos;
|
||||
|
||||
index_type i = 1;
|
||||
double length = 0;
|
||||
while (i <= STEPS_PER_SEGMENT)
|
||||
{
|
||||
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_Bezier3Coeffs, nextPos);
|
||||
length += (nextPos - curPos).length();
|
||||
curPos = nextPos;
|
||||
++i;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void SplineBase::init_spline(const Vector3 * controls, index_type count, EvaluationMode m)
|
||||
{
|
||||
m_mode = m;
|
||||
cyclic = false;
|
||||
|
||||
(this->*initializers[m_mode])(controls, count, cyclic, 0);
|
||||
}
|
||||
|
||||
void SplineBase::init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point)
|
||||
{
|
||||
m_mode = m;
|
||||
cyclic = true;
|
||||
|
||||
(this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
|
||||
}
|
||||
|
||||
void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
|
||||
{
|
||||
ASSERT(count >= 2);
|
||||
const int real_size = count + 1;
|
||||
|
||||
points.resize(real_size);
|
||||
|
||||
memcpy(&points[0], controls, sizeof(Vector3) * count);
|
||||
|
||||
// first and last two indexes are space for special 'virtual points'
|
||||
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
|
||||
if (cyclic)
|
||||
points[count] = controls[cyclic_point];
|
||||
else
|
||||
points[count] = controls[count-1];
|
||||
|
||||
index_lo = 0;
|
||||
index_hi = cyclic ? count : (count - 1);
|
||||
}
|
||||
|
||||
void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
|
||||
{
|
||||
const int real_size = count + (cyclic ? (1+2) : (1+1));
|
||||
|
||||
points.resize(real_size);
|
||||
|
||||
int lo_index = 1;
|
||||
int high_index = lo_index + count - 1;
|
||||
|
||||
memcpy(&points[lo_index], controls, sizeof(Vector3) * count);
|
||||
|
||||
// first and last two indexes are space for special 'virtual points'
|
||||
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
|
||||
if (cyclic)
|
||||
{
|
||||
if (cyclic_point == 0)
|
||||
points[0] = controls[count-1];
|
||||
else
|
||||
points[0] = controls[0].lerp(controls[1], -1);
|
||||
|
||||
points[high_index+1] = controls[cyclic_point];
|
||||
points[high_index+2] = controls[cyclic_point+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
points[0] = controls[0].lerp(controls[1], -1);
|
||||
points[high_index+1] = controls[count-1];
|
||||
}
|
||||
|
||||
index_lo = lo_index;
|
||||
index_hi = high_index + (cyclic ? 1 : 0);
|
||||
}
|
||||
|
||||
void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/)
|
||||
{
|
||||
index_type c = count / 3u * 3u;
|
||||
index_type t = c / 3u;
|
||||
|
||||
points.resize(c);
|
||||
memcpy(&points[0], controls, sizeof(Vector3) * c);
|
||||
|
||||
index_lo = 0;
|
||||
index_hi = t-1;
|
||||
//mov_assert(points.size() % 3 == 0);
|
||||
}
|
||||
|
||||
void SplineBase::clear()
|
||||
{
|
||||
index_lo = 0;
|
||||
index_hi = 0;
|
||||
points.clear();
|
||||
pointsVisual.clear();
|
||||
}
|
||||
|
||||
std::string SplineBase::ToString() const
|
||||
{
|
||||
std::stringstream str;
|
||||
const char * mode_str[ModesEnd] = {"Linear", "CatmullRom", "Bezier3", "Uninitialized"};
|
||||
|
||||
index_type count = this->points.size();
|
||||
str << "mode: " << mode_str[mode()] << std::endl;
|
||||
str << "points count: " << count << std::endl;
|
||||
for (index_type i = 0; i < count; ++i)
|
||||
str << "point " << i << " : " << points[i].toString() << std::endl;
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
}
|
||||
215
src/server/game/Movement/Spline/Spline.h
Normal file
215
src/server/game/Movement/Spline/Spline.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_SPLINE_H
|
||||
#define TRINITYSERVER_SPLINE_H
|
||||
|
||||
#include "MovementTypedefs.h"
|
||||
#include <G3D/Vector3.h>
|
||||
#include <limits>
|
||||
|
||||
namespace Movement {
|
||||
|
||||
class SplineBase
|
||||
{
|
||||
public:
|
||||
typedef int index_type;
|
||||
typedef std::vector<Vector3> ControlArray;
|
||||
|
||||
enum EvaluationMode
|
||||
{
|
||||
ModeLinear,
|
||||
ModeCatmullrom,
|
||||
ModeBezier3_Unused,
|
||||
UninitializedMode,
|
||||
ModesEnd
|
||||
};
|
||||
|
||||
protected:
|
||||
ControlArray points;
|
||||
ControlArray pointsVisual;
|
||||
|
||||
index_type index_lo;
|
||||
index_type index_hi;
|
||||
|
||||
uint8 m_mode;
|
||||
bool cyclic;
|
||||
|
||||
enum{
|
||||
// could be modified, affects segment length evaluation precision
|
||||
// lesser value saves more performance in cost of lover precision
|
||||
// minimal value is 1
|
||||
// client's value is 20, blizzs use 2-3 steps to compute length
|
||||
STEPS_PER_SEGMENT = 3
|
||||
};
|
||||
static_assert(STEPS_PER_SEGMENT > 0, "shouldn't be lesser than 1");
|
||||
|
||||
protected:
|
||||
void EvaluateLinear(index_type, float, Vector3&) const;
|
||||
void EvaluateCatmullRom(index_type, float, Vector3&) const;
|
||||
void EvaluateBezier3(index_type, float, Vector3&) const;
|
||||
typedef void (SplineBase::*EvaluationMethtod)(index_type, float, Vector3&) const;
|
||||
static EvaluationMethtod evaluators[ModesEnd];
|
||||
|
||||
void EvaluateDerivativeLinear(index_type, float, Vector3&) const;
|
||||
void EvaluateDerivativeCatmullRom(index_type, float, Vector3&) const;
|
||||
void EvaluateDerivativeBezier3(index_type, float, Vector3&) const;
|
||||
static EvaluationMethtod derivative_evaluators[ModesEnd];
|
||||
|
||||
float SegLengthLinear(index_type) const;
|
||||
float SegLengthCatmullRom(index_type) const;
|
||||
float SegLengthBezier3(index_type) const;
|
||||
typedef float (SplineBase::*SegLenghtMethtod)(index_type) const;
|
||||
static SegLenghtMethtod seglengths[ModesEnd];
|
||||
|
||||
void InitLinear(const Vector3*, index_type, bool, index_type);
|
||||
void InitCatmullRom(const Vector3*, index_type, bool, index_type);
|
||||
void InitBezier3(const Vector3*, index_type, bool, index_type);
|
||||
typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type);
|
||||
static InitMethtod initializers[ModesEnd];
|
||||
|
||||
void UninitializedSpline() const { ASSERT(false);}
|
||||
|
||||
public:
|
||||
|
||||
explicit SplineBase() : index_lo(0), index_hi(0), m_mode(UninitializedMode), cyclic(false) {}
|
||||
|
||||
/** Caclulates the position for given segment Idx, and percent of segment length t
|
||||
@param t - percent of segment length, assumes that t in range [0, 1]
|
||||
@param Idx - spline segment index, should be in range [first, last)
|
||||
*/
|
||||
void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx, u,c);}
|
||||
|
||||
/** Caclulates derivation in index Idx, and percent of segment length t
|
||||
@param Idx - spline segment index, should be in range [first, last)
|
||||
@param t - percent of spline segment length, assumes that t in range [0, 1]
|
||||
*/
|
||||
void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx, u,hermite);}
|
||||
|
||||
/** Bounds for spline indexes. All indexes should be in range [first, last). */
|
||||
index_type first() const { return index_lo;}
|
||||
index_type last() const { return index_hi;}
|
||||
|
||||
bool empty() const { return index_lo == index_hi;}
|
||||
EvaluationMode mode() const { return (EvaluationMode)m_mode;}
|
||||
bool isCyclic() const { return cyclic;}
|
||||
|
||||
// Xinef: DO NOT USE EXCEPT FOR SPLINE INITIALIZATION!!!!!!
|
||||
const ControlArray* allocateVisualPoints() const { return &pointsVisual; }
|
||||
const ControlArray& getPoints(bool visual) const { return visual ? pointsVisual : points;}
|
||||
index_type getPointCount() const { return points.size();}
|
||||
const Vector3& getPoint(index_type i, bool visual) const { return visual ? pointsVisual[i] : points[i];}
|
||||
|
||||
/** Initializes spline. Don't call other methods while spline not initialized. */
|
||||
void init_spline(const Vector3 * controls, index_type count, EvaluationMode m);
|
||||
void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point);
|
||||
|
||||
/** As i can see there are a lot of ways how spline can be initialized
|
||||
would be no harm to have some custom initializers. */
|
||||
template<class Init> inline void init_spline_custom(Init& initializer)
|
||||
{
|
||||
initializer(m_mode, cyclic, points, index_lo, index_hi);
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
/** Calculates distance between [i; i+1] points, assumes that index i is in bounds. */
|
||||
float SegLength(index_type i) const { return (this->*seglengths[m_mode])(i);}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
template<typename length_type>
|
||||
class Spline : public SplineBase
|
||||
{
|
||||
public:
|
||||
typedef length_type LengthType;
|
||||
typedef std::vector<length_type> LengthArray;
|
||||
protected:
|
||||
|
||||
LengthArray lengths;
|
||||
|
||||
index_type computeIndexInBounds(length_type length) const;
|
||||
public:
|
||||
|
||||
explicit Spline(){}
|
||||
|
||||
/** Calculates the position for given t
|
||||
@param t - percent of spline's length, assumes that t in range [0, 1]. */
|
||||
void evaluate_percent(float t, Vector3 & c) const;
|
||||
|
||||
/** Calculates derivation for given t
|
||||
@param t - percent of spline's length, assumes that t in range [0, 1]. */
|
||||
void evaluate_derivative(float t, Vector3& hermite) const;
|
||||
|
||||
/** Calculates the position for given segment Idx, and percent of segment length t
|
||||
@param t = partial_segment_length / whole_segment_length
|
||||
@param Idx - spline segment index, should be in range [first, last). */
|
||||
void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx, u,c);}
|
||||
|
||||
/** Caclulates derivation for index Idx, and percent of segment length t
|
||||
@param Idx - spline segment index, should be in range [first, last)
|
||||
@param t - percent of spline segment length, assumes that t in range [0, 1]. */
|
||||
void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx, u,c);}
|
||||
|
||||
// Assumes that t in range [0, 1]
|
||||
index_type computeIndexInBounds(float t) const;
|
||||
void computeIndex(float t, index_type& out_idx, float& out_u) const;
|
||||
|
||||
/** Initializes spline. Don't call other methods while spline not initialized. */
|
||||
void init_spline(const Vector3 * controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);}
|
||||
void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m,cyclic_point);}
|
||||
|
||||
/** Initializes lengths with SplineBase::SegLength method. */
|
||||
void initLengths();
|
||||
|
||||
/** Initializes lengths in some custom way
|
||||
Note that value returned by cacher must be greater or equal to previous value. */
|
||||
template<class T> inline void initLengths(T& cacher)
|
||||
{
|
||||
index_type i = index_lo;
|
||||
lengths.resize(index_hi+1);
|
||||
length_type prev_length = 0, new_length = 0;
|
||||
while (i < index_hi)
|
||||
{
|
||||
new_length = cacher(*this, i);
|
||||
// length overflowed, assign to max positive value
|
||||
if (new_length < 0)
|
||||
new_length = std::numeric_limits<length_type>::max();
|
||||
lengths[++i] = new_length;
|
||||
|
||||
ASSERT(prev_length <= new_length);
|
||||
prev_length = new_length;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns length of the whole spline. */
|
||||
length_type length() const { return lengths[index_hi];}
|
||||
/** Returns length between given nodes. */
|
||||
length_type length(index_type first, index_type last) const { return lengths[last]-lengths[first];}
|
||||
length_type length(index_type Idx) const { return lengths[Idx];}
|
||||
|
||||
void set_length(index_type i, length_type length) { lengths[i] = length;}
|
||||
void clear();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "SplineImpl.h"
|
||||
|
||||
#endif // TRINITYSERVER_SPLINE_H
|
||||
97
src/server/game/Movement/Spline/SplineImpl.h
Normal file
97
src/server/game/Movement/Spline/SplineImpl.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
template<typename length_type> void Spline<length_type>::evaluate_percent( float t, Vector3 & c ) const
|
||||
{
|
||||
index_type Index;
|
||||
float u;
|
||||
computeIndex(t, Index, u);
|
||||
evaluate_percent(Index, u, c);
|
||||
}
|
||||
|
||||
template<typename length_type> void Spline<length_type>::evaluate_derivative(float t, Vector3& hermite) const
|
||||
{
|
||||
index_type Index;
|
||||
float u;
|
||||
computeIndex(t, Index, u);
|
||||
evaluate_derivative(Index, u, hermite);
|
||||
}
|
||||
|
||||
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds(length_type length_) const
|
||||
{
|
||||
// Temporary disabled: causes infinite loop with t = 1.f
|
||||
/*
|
||||
index_type hi = index_hi;
|
||||
index_type lo = index_lo;
|
||||
|
||||
index_type i = lo + (float)(hi - lo) * t;
|
||||
|
||||
while ((lengths[i] > length) || (lengths[i + 1] <= length))
|
||||
{
|
||||
if (lengths[i] > length)
|
||||
hi = i - 1; // too big
|
||||
else if (lengths[i + 1] <= length)
|
||||
lo = i + 1; // too small
|
||||
|
||||
i = (hi + lo) / 2;
|
||||
}*/
|
||||
|
||||
index_type i = index_lo;
|
||||
index_type N = index_hi;
|
||||
while (i+1 < N && lengths[i+1] < length_)
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
template<typename length_type> void Spline<length_type>::computeIndex(float t, index_type& index, float& u) const
|
||||
{
|
||||
ASSERT(t >= 0.f && t <= 1.f);
|
||||
length_type length_ = t * length();
|
||||
index = computeIndexInBounds(length_);
|
||||
ASSERT(index < index_hi);
|
||||
u = (length_ - length(index)) / (float)length(index, index+1);
|
||||
}
|
||||
|
||||
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds( float t ) const
|
||||
{
|
||||
ASSERT(t >= 0.f && t <= 1.f);
|
||||
return computeIndexInBounds(t * length());
|
||||
}
|
||||
|
||||
template<typename length_type> void Spline<length_type>::initLengths()
|
||||
{
|
||||
index_type i = index_lo;
|
||||
length_type length = 0;
|
||||
lengths.resize(index_hi+1);
|
||||
while (i < index_hi)
|
||||
{
|
||||
length += SegLength(i);
|
||||
lengths[++i] = length;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename length_type> void Spline<length_type>::clear()
|
||||
{
|
||||
SplineBase::clear();
|
||||
lengths.clear();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user