
#pragma once

#include "../BoundingBox.h"
#include "../Item.h"
#include "../OSSupport/AtomicUniquePtr.h"





// Place this macro in the public section of each cEntity descendant class and you're done :)
#define CLASS_PROTODEF(classname) \
	virtual bool IsA(const char * a_ClassName) const override\
	{ \
		return ((a_ClassName != nullptr) && ((strcmp(a_ClassName, #classname) == 0) || Super::IsA(a_ClassName))); \
	} \
	virtual const char * GetClass(void) const override \
	{ \
		return #classname; \
	} \
	static const char * GetClassStatic(void) \
	{ \
		return #classname; \
	} \
	virtual const char * GetParentClass(void) const override \
	{ \
		return Super::GetClass(); \
	}

#define POSX_TOINT FloorC(GetPosX())
#define POSY_TOINT FloorC(GetPosY())
#define POSZ_TOINT FloorC(GetPosZ())
#define POS_TOINT  GetPosition().Floor()

#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z) \
	cChunk * ChunkVarName = a_Chunk.GetNeighborChunk(X, Z); \
	do { \
		if ((ChunkVarName == nullptr) || !ChunkVarName->IsValid()) \
		{ \
			return; \
		} \
	} while (false)




class cWorld;
class cClientHandle;
class cPlayer;
class cChunk;
class cMonster;





// tolua_begin
struct TakeDamageInfo
{
	eDamageType DamageType;   // Where does the damage come from? Being hit / on fire / contact with cactus / ...
	cEntity *   Attacker;     // The attacking entity; valid only for dtAttack
	int         RawDamage;    // What damage would the receiver get without any armor. Usually: attacker mob type + weapons
	float       FinalDamage;  // What actual damage will be received. Usually: m_RawDamage minus armor
	Vector3d    Knockback;    // The amount and direction of knockback received from the damage
	// TODO: Effects - list of effects that the hit is causing. Unknown representation yet
} ;
// tolua_end





// tolua_begin
class cEntity
{
protected:
	/** State variables for MoveToWorld. */
	struct sWorldChangeInfo
	{
		cWorld * m_NewWorld;
		Vector3d m_NewPosition;
		bool m_SetPortalCooldown;
	};

public:

	enum eEntityType
	{
		etEntity,  // For all other types
		etEnderCrystal,
		etPlayer,
		etPickup,
		etMonster,
		etFallingBlock,
		etMinecart,
		etBoat,
		etTNT,
		etProjectile,
		etExpOrb,
		etFloater,
		etItemFrame,
		etPainting,
		etLeashKnot,

		// Common variations
		etMob = etMonster,  // DEPRECATED, use etMonster instead!
	} ;

	// tolua_end

	static const int FIRE_TICKS_PER_DAMAGE = 10;   ///< Ticks to wait between damaging an entity when it stands in fire
	static const int FIRE_DAMAGE           = 1;    ///< Damage to deal when standing in fire
	static const int LAVA_TICKS_PER_DAMAGE = 10;   ///< Ticks to wait between damaging an entity when it stands in lava
	static const int LAVA_DAMAGE           = 4;    ///< Damage to deal when standing in lava
	static const int BURN_TICKS_PER_DAMAGE = 20;   ///< Ticks to wait between damaging an entity when it is burning
	static const int BURN_DAMAGE           = 1;    ///< Damage to deal when the entity is burning

	static const int BURN_TICKS            = 160;  ///< Ticks to keep an entity burning after it has stood in lava / fire

	static const int MAX_AIR_LEVEL         = 300;  ///< Maximum air an entity can have
	static const int DROWNING_TICKS        = 20;   ///< Number of ticks per heart of damage

	static const int VOID_BOUNDARY         = -64;  ///< Y position to begin applying void damage
	static const int FALL_DAMAGE_HEIGHT    = 4;    ///< Y difference after which fall damage is applied

	/** Special ID that is considered an "invalid value", signifying no entity. */
	static const UInt32 INVALID_ID = 0;  // Exported to Lua in ManualBindings.cpp, ToLua doesn't parse initialized constants.


	cEntity(eEntityType a_EntityType, Vector3d a_Pos, float a_Width, float a_Height);
	virtual ~cEntity() = default;

	/** Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed).
	Adds the entity to the world. */
	bool Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld);

	/** Called when a player begins spectating this entity. */
	void OnAcquireSpectator(cPlayer & a_Player);

	/** Called when the entity is added to a world.
	e.g after first spawning or after successfuly moving between worlds.
	\param a_World The world being added to. */
	virtual void OnAddToWorld(cWorld & a_World);

	/** Called when a player stops spectating this entity. */
	void OnLoseSpectator(cPlayer & a_Player);

	/** Called when the entity is removed from a world.
	e.g. When the entity is destroyed or moved to a different world.
	\param a_World The world being removed from. */
	virtual void OnRemoveFromWorld(cWorld & a_World);

	// tolua_begin

	eEntityType GetEntityType(void) const { return m_EntityType; }

	bool IsArrow       (void) const { return IsA("cArrowEntity");              }
	bool IsEnderCrystal(void) const { return (m_EntityType == etEnderCrystal); }
	bool IsPlayer      (void) const { return (m_EntityType == etPlayer);       }
	bool IsPickup      (void) const { return (m_EntityType == etPickup);       }
	bool IsMob         (void) const { return (m_EntityType == etMonster);      }
	bool IsPawn        (void) const { return (IsMob() || IsPlayer());          }
	bool IsFallingBlock(void) const { return (m_EntityType == etFallingBlock); }
	bool IsMinecart    (void) const { return (m_EntityType == etMinecart);     }
	bool IsBoat        (void) const { return (m_EntityType == etBoat);         }
	bool IsTNT         (void) const { return (m_EntityType == etTNT);          }
	bool IsProjectile  (void) const { return (m_EntityType == etProjectile);   }
	bool IsExpOrb      (void) const { return (m_EntityType == etExpOrb);       }
	bool IsFloater     (void) const { return (m_EntityType == etFloater);      }
	bool IsItemFrame   (void) const { return (m_EntityType == etItemFrame);    }
	bool IsLeashKnot   (void) const { return (m_EntityType == etLeashKnot);    }
	bool IsPainting    (void) const { return (m_EntityType == etPainting);     }

	/** Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true) */
	virtual bool IsA(const char * a_ClassName) const;

	/** Returns the class name of this class */
	static const char * GetClassStatic(void);

	/** Returns the topmost class name for the object */
	virtual const char * GetClass(void) const;

	/** Returns the topmost class's parent class name for the object. cEntity returns an empty string (no parent). */
	virtual const char * GetParentClass(void) const;

	/** Returns whether blocks can be placed intersecting this entities' hitbox */
	virtual bool DoesPreventBlockPlacement(void) const { return true; }

	cWorld * GetWorld(void) const { return m_World; }

	double           GetHeadYaw   (void) const { return m_HeadYaw; }  // In degrees
	float            GetHeight    (void) const { return m_Height;  }
	double           GetMass      (void) const { return m_Mass;    }
	double           GetPosX      (void) const { return m_Position.x; }
	double           GetPosY      (void) const { return m_Position.y; }
	double           GetPosZ      (void) const { return m_Position.z; }
	double           GetYaw       (void) const { return m_Rot.x;   }  // In degrees, [-180, +180)
	double           GetPitch     (void) const { return m_Rot.y;   }  // In degrees, [-180, +180), but normal client clips to [-90, +90]
	double           GetRoll      (void) const { return m_Rot.z;   }  // In degrees, unused in current client
	Vector3d         GetLookVector(void) const;
	double           GetSpeedX    (void) const { return m_Speed.x; }
	double           GetSpeedY    (void) const { return m_Speed.y; }
	double           GetSpeedZ    (void) const { return m_Speed.z; }
	float            GetWidth     (void) const { return m_Width;   }

	int GetChunkX(void) const { return FloorC(m_Position.x / cChunkDef::Width); }
	int GetChunkZ(void) const { return FloorC(m_Position.z / cChunkDef::Width); }

	// Get the Entity's axis aligned bounding box, with absolute (world-relative) coordinates.
	cBoundingBox GetBoundingBox() const { return cBoundingBox(GetPosition(), GetWidth() / 2, GetHeight()); }

	void SetHeadYaw (double a_HeadYaw);
	void SetMass    (double a_Mass);
	void SetPosX    (double a_PosX) { SetPosition({a_PosX, m_Position.y, m_Position.z}); }
	void SetPosY    (double a_PosY) { SetPosition({m_Position.x, a_PosY, m_Position.z}); }
	void SetPosZ    (double a_PosZ) { SetPosition({m_Position.x, m_Position.y, a_PosZ}); }
	void SetPosition(double a_PosX, double a_PosY, double a_PosZ) { SetPosition({a_PosX, a_PosY, a_PosZ}); }
	void SetPosition(const Vector3d & a_Position);
	void SetYaw     (double a_Yaw);    // In degrees, normalizes to [-180, +180)
	void SetPitch   (double a_Pitch);  // In degrees, normalizes to [-180, +180)
	void SetRoll    (double a_Roll);   // In degrees, normalizes to [-180, +180)

	/** Sets the speed of the entity, measured in m / sec */
	void SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ);

	/** Sets the speed of the entity, measured in m / sec */
	void SetSpeed(Vector3d a_Speed) { SetSpeed(a_Speed.x, a_Speed.y, a_Speed.z); }

	/** Sets the speed in the X axis, leaving the other speed components intact. Measured in m / sec. */
	void SetSpeedX(double a_SpeedX);

	/** Sets the speed in the Y axis, leaving the other speed components intact. Measured in m / sec. */
	void SetSpeedY(double a_SpeedY);

	/** Sets the speed in the Z axis, leaving the other speed components intact. Measured in m / sec. */
	void SetSpeedZ(double a_SpeedZ);

	void AddPosX    (double a_AddPosX) { AddPosition(a_AddPosX, 0, 0); }
	void AddPosY    (double a_AddPosY) { AddPosition(0, a_AddPosY, 0); }
	void AddPosZ    (double a_AddPosZ) { AddPosition(0, 0, a_AddPosZ); }
	void AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ) { SetPosition(m_Position + Vector3d(a_AddPosX, a_AddPosY, a_AddPosZ)); }
	void AddPosition(const Vector3d & a_AddPos) { AddPosition(a_AddPos.x, a_AddPos.y, a_AddPos.z); }
	void AddSpeed   (double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeedZ);
	void AddSpeed   (const Vector3d & a_AddSpeed) { AddSpeed(a_AddSpeed.x, a_AddSpeed.y, a_AddSpeed.z); }
	void AddSpeedX  (double a_AddSpeedX);
	void AddSpeedY  (double a_AddSpeedY);
	void AddSpeedZ  (double a_AddSpeedZ);

	virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways);
	void SteerVehicle(float a_Forward, float a_Sideways);

	inline UInt32 GetUniqueID(void) const { return m_UniqueID; }

	/** Deprecated. Use IsTicking instead. */
	inline bool IsDestroyed() const {return !IsTicking();}

	/** Returns true if the entity is valid and ticking. Returns false if the entity is not ticking and is about to leave
	its current world either via teleportation or destruction.
	If this returns false, you must stop using the cEntity pointer you have. */
	bool IsTicking(void) const;

	// tolua_end
	/** Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet */
	void Destroy();
	// tolua_begin

	/** Makes this pawn take damage from an attack by a_Attacker. Damage values are calculated automatically and DoTakeDamage() called */
	void TakeDamage(cEntity & a_Attacker);

	/** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */
	void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount);

	/** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */
	void TakeDamage(eDamageType a_DamageType, UInt32 a_Attacker, int a_RawDamage, double a_KnockbackAmount);

	/** Makes this entity take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage() */
	void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, float a_FinalDamage, double a_KnockbackAmount);

	float GetGravity(void) const { return m_Gravity; }

	void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; }

	float GetAirDrag(void) const { return m_AirDrag; }

	void SetAirDrag(float a_AirDrag) { m_AirDrag = a_AirDrag; }

	/** Sets the rotation to match the speed vector (entity goes "face-forward") */
	void SetYawFromSpeed(void);

	/** Sets the pitch to match the speed vector (entity gies "face-forward") */
	void SetPitchFromSpeed(void);

	// tolua_end

	/** Exported in ManualBindings */
	const Vector3d & GetPosition(void) const { return m_Position; }

	/** Exported in ManualBindings */
	const Vector3d & GetSpeed(void) const { return m_Speed; }

	/** Returns the last position we sent to all the clients. Use this to
	initialize clients with our position. */
	Vector3d GetLastSentPosition(void) const { return m_LastSentPosition; }

	/** Makes this entity take damage specified in the a_TDI.
	The TDI is sent through plugins first, then applied.
	If it returns false, the entity hasn't receive any damage. */
	virtual bool DoTakeDamage(TakeDamageInfo & a_TDI);

	// tolua_begin

	/** Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items */
	virtual int GetRawDamageAgainst(const cEntity & a_Receiver);

	/** Returns whether armor will protect against the specified damage type */
	virtual bool ArmorCoversAgainst(eDamageType a_DamageType);

	/** Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover */
	virtual float GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage);

	/** Returns the hitpoints that the currently equipped armor's enchantments would cover */
	virtual float GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage);

	/** Returns explosion knock back reduction percent from blast protection level
	@return knock back reduce percent */
	virtual float GetEnchantmentBlastKnockbackReduction();

	/** Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit */
	virtual double GetKnockbackAmountAgainst(const cEntity & a_Receiver);

	/** Returns the curently equipped weapon; empty item if none */
	virtual cItem GetEquippedWeapon(void) const { return cItem(); }

	/** Returns the currently equipped helmet; empty item if none */
	virtual cItem GetEquippedHelmet(void) const { return cItem(); }

	/** Returns the currently equipped chestplate; empty item if none */
	virtual cItem GetEquippedChestplate(void) const { return cItem(); }

	/** Returns the currently equipped leggings; empty item if none */
	virtual cItem GetEquippedLeggings(void) const { return cItem(); }

	/** Returns the currently equipped boots; empty item if none */
	virtual cItem GetEquippedBoots(void) const { return cItem(); }

	/** Returns the currently offhand equipped item; empty item if none */
	virtual cItem GetOffHandEquipedItem(void) const { return cItem(); }

	/** Applies damage to the armor after the armor blocked the given amount */
	virtual void ApplyArmorDamage(int DamageBlocked);

	// tolua_end

	/** Called when the health drops below zero. a_TDI's Attacker may be nullptr (environmental damage) */
	virtual void KilledBy(TakeDamageInfo & a_TDI);

	// tolua_begin

	/** Called when the entity kills another entity. */
	virtual void Killed(const cEntity & a_Victim, eDamageType a_DamageType) {}

	/** Heals the specified amount of HPs */
	virtual void Heal(int a_HitPoints);

	/** Returns the health of this entity */
	float GetHealth(void) const { return m_Health; }

	/** Sets the health of this entity; doesn't broadcast any hurt animation */
	void SetHealth(float a_Health);

	// tolua_end

	virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);

	/** Handles the physics of the entity - updates position based on speed, updates speed based on environment */
	virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);

	/** Updates the state related to this entity being on fire */
	virtual void TickBurning(cChunk & a_Chunk);

	/** Detects the time for application of cacti damage */
	virtual void DetectCacti(void);

	/** Detects the time for application of magma block damage */
	virtual void DetectMagma(void);

	/** Detects whether we are in a portal block and begins teleportation procedures if so
	Returns true if MoveToWorld() was called, false if not
	*/
	virtual bool DetectPortal(void);

	/** Handles when the entity is in the void */
	virtual void TickInVoid(cChunk & a_Chunk);

	/** Called when the entity starts burning */
	virtual void OnStartedBurning(void);

	/** Called when the entity finishes burning */
	virtual void OnFinishedBurning(void);

	// tolua_begin

	/** Sets the maximum value for the health */
	void SetMaxHealth(float a_MaxHealth);

	float GetMaxHealth(void) const { return m_MaxHealth; }

	/** Sets whether the entity is fireproof */
	void SetIsFireproof(bool a_IsFireproof);

	virtual bool IsFireproof(void) const { return m_IsFireproof; }

	/** Puts the entity on fire for the specified amount of ticks */
	void StartBurning(int a_TicksLeftBurning);

	/** Stops the entity from burning, resets all burning timers */
	void StopBurning(void);

	// tolua_end

	/** Descendants override this function to send a command to the specified client to spawn the entity on the client.
	To spawn on all eligible clients, use cChunkMap::BroadcastSpawnEntity() */
	virtual void SpawnOn(cClientHandle & a_Client) = 0;

	// tolua_begin

	/** Teleports to the entity specified */
	virtual void TeleportToEntity(cEntity & a_Entity);

	/** Teleports to the coordinates specified */
	virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ);

	bool MoveToWorld(cWorld & a_World, Vector3d a_NewPosition, bool a_ShouldSetPortalCooldown = false, bool a_ShouldSendRespawn = true);

	bool MoveToWorld(cWorld & a_World, bool a_ShouldSendRespawn, Vector3d a_NewPosition)
	{
		return MoveToWorld(a_World, a_NewPosition, false, a_ShouldSendRespawn);
	}

	/** Moves entity to specified world, taking a world pointer */
	bool MoveToWorld(cWorld & a_World, bool a_ShouldSendRespawn = true);

	/** Moves entity to specified world, taking a world name */
	bool MoveToWorld(const AString & a_WorldName, bool a_ShouldSendRespawn = true);

	// tolua_end

	/** Returns true if a world change is scheduled to happen. */
	bool IsWorldChangeScheduled() const
	{
		return (m_WorldChangeInfo.m_NewWorld != nullptr);
	}

	/** Updates clients of changes in the entity. */
	virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = nullptr);

	/** Gets entity (vehicle) attached to this entity */
	cEntity * GetAttached();

	/** Attaches to the specified entity; detaches from any previous one first. */
	void AttachTo(cEntity & a_AttachTo);

	/** Detaches from the currently attached entity, if any. */
	void Detach(void);

	/** Returns true if this entity is attached to the specified entity */
	bool IsAttachedTo(const cEntity * a_Entity) const;

	/** Returns whether the entity's orientation has been set manually.
	Primarily inteded for protocol use. */
	bool IsOrientationDirty() const;

	/** Makes sure head yaw is not over the specified range. */
	void WrapHeadYaw();

	/** Makes sure rotation is not over the specified range. */
	void WrapRotation();

	/** Makes speed is not over 20. Max speed is 20 blocks / second */
	void WrapSpeed();

	// tolua_begin

	// COMMON metadata flags; descendants may override the defaults:
	virtual bool IsCrouched    (void) const { return false; }
	virtual bool IsElytraFlying(void) const { return false; }
	virtual bool IsInvisible   (void) const { return false; }
	virtual bool IsOnFire      (void) const { return m_TicksLeftBurning > 0; }
	virtual bool IsRclking     (void) const { return false; }
	virtual bool IsRiding      (void) const { return false; }
	virtual bool IsSprinting   (void) const { return false; }

	/** Returns true if any part of the entity is in a fire block */
	virtual bool IsInFire(void) const { return m_IsInFire; }

	/** Returns true if any part of the entity is in a lava block */
	virtual bool IsInLava(void) const { return m_IsInLava; }

	/** Returns true if any part of the entity is in a water block */
	virtual bool IsInWater(void) const { return m_IsInWater; }

	/** Returns true if any part of the entity is in a water block */
	virtual bool IsHeadInWater(void) const { return m_IsHeadInWater; }

	/** Gets remaining air of a monster */
	int GetAirLevel(void) const { return m_AirLevel; }

	/** Gets number of ticks this entity has been alive for */
	long int GetTicksAlive(void) const { return m_TicksAlive; }

	/** Gets the invulnerable ticks from the entity */
	int GetInvulnerableTicks(void) const { return m_InvulnerableTicks; }

	/** Set the invulnerable ticks from the entity */
	void SetInvulnerableTicks(int a_InvulnerableTicks) { m_InvulnerableTicks = a_InvulnerableTicks; }

	/** Returns whether the entity is on ground or not */
	virtual bool IsOnGround(void) const { return m_bOnGround; }

	// tolua_end

	/** Called when the specified player right-clicks this entity */
	virtual void OnRightClicked(cPlayer & a_Player) {}

	/** Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy(). */
	virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr)
	{
		UNUSED(a_Drops);
		UNUSED(a_Killer);
	}

	/** Sets the internal world pointer to a new cWorld, doesn't update anything else. */
	void SetWorld(cWorld * a_World) { m_World = a_World; }

	/** Sets the parent chunk, which is the chunk responsible for ticking this entity.
	Only cChunk::AddEntity and cChunk::RemoveEntity cChunk::~cChunk should ever call this. */
	void SetParentChunk(cChunk * a_Chunk);

	/** Returns the chunk responsible for ticking this entity. */
	cChunk * GetParentChunk() { return m_ParentChunk; }
	const cChunk * GetParentChunk() const { return m_ParentChunk; }

	/** Set the entity's status to either ticking or not ticking. */
	void SetIsTicking(bool a_IsTicking);

	/** Update an entity's size, for example, on body stance changes. */
	void SetSize(float a_Width, float a_Height);

	/** Adds a mob to the leashed list of mobs. */
	void AddLeashedMob(cMonster * a_Monster);

	/** Removes a mob from the leashed list of mobs. */
	void RemoveLeashedMob(cMonster * a_Monster);

	/** Returs whether the entity has any mob leashed to it. */
	bool HasAnyMobLeashed() const { return m_LeashedMobs.size() > 0; }

	/** Announces a death message on chat about killing the entity. */
	void BroadcastDeathMessage(TakeDamageInfo & a_TDI);

protected:

	/** Structure storing the portal delay timer and cooldown boolean */
	struct sPortalCooldownData
	{
		/** Ticks since entry of portal, used to delay teleportation */
		unsigned short m_TicksDelayed;

		/** Whether the entity has just exited the portal, and should therefore not be teleported again.
		This prevents teleportation loops, and is reset when the entity has moved out of the portal. */
		bool m_ShouldPreventTeleportation;
	};


	/** Measured in meters / second (m / s) */
	Vector3d m_Speed;

	/** The ID of the entity that is guaranteed to be unique within a single run of the server.
	Always nonzero (a zero UniqueID (cEntity::INVALID_ID) is used for error reporting).
	Note that the UniqueID is not persisted through storage. */
	UInt32 m_UniqueID;

	float m_Health;
	float m_MaxHealth;

	/** The entity to which this entity is attached (vehicle), nullptr if none. */
	cEntity * m_AttachedTo;

	/** The entity which is attached to this entity (rider), nullptr if none. */
	cEntity * m_Attachee;

	/** Stores whether head yaw has been set manually */
	bool m_bDirtyHead;

	/** Stores whether our yaw / pitch / roll (body orientation) has been set manually */
	bool m_bDirtyOrientation;

	/** Stores whether we have sent a Velocity packet with a speed of zero (no speed) to the client
	Ensures that said packet is sent only once */
	bool m_bHasSentNoSpeed;

	/** Stores if the entity is on the ground */
	bool m_bOnGround;

	/** Stores gravity that is applied to an entity every tick
	For realistic effects, this should be negative. For spaaaaaaace, this can be zero or even positive */
	float m_Gravity;

	/** Stores the air drag that is applied to the entity every tick, measured in speed ratio per tick
	Acts as air friction and slows down flight
	Will be interpolated if the server tick rate varies
	Data: https://minecraft.wiki/w/Entity#Motion_of_entities */
	float m_AirDrag;

	/** Last position sent to client via the Relative Move or Teleport packets (not Velocity)
	Only updated if cEntity::BroadcastMovementUpdate() is called! */
	Vector3d m_LastSentPosition;

	Vector3d m_LastPosition;

	eEntityType m_EntityType;

	cWorld * m_World;

	/** If field m_NewWorld not nullptr, a world change is scheduled and a task is queued in the current world. */
	sWorldChangeInfo m_WorldChangeInfo;

	/** Whether the entity is capable of taking fire or lava damage. */
	bool m_IsFireproof;

	/** Time, in ticks, since the last damage dealt by being on fire. Valid only if on fire (IsOnFire()) */
	int m_TicksSinceLastBurnDamage;

	/** Time, in ticks, since the last damage dealt by standing in lava. Reset to zero when moving out of lava. */
	int m_TicksSinceLastLavaDamage;

	/** Time, in ticks, since the last damage dealt by standing in fire. Reset to zero when moving out of fire. */
	int m_TicksSinceLastFireDamage;

	/** Time, in ticks, until the entity extinguishes its fire */
	int m_TicksLeftBurning;

	/** Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void. */
	int m_TicksSinceLastVoidDamage;

	/** If any part of the entity is in a fire block */
	bool m_IsInFire;

	/** If any part of the entity is in a lava block */
	bool m_IsInLava;

	/** If any part of the entity is in a water block */
	bool m_IsInWater;

	/** If the entity's head is in a water block */
	bool m_IsHeadInWater;

	/** Air level of a mobile */
	int m_AirLevel;
	int m_AirTickTimer;

	/** Portal delay timer and cooldown boolean data */
	sPortalCooldownData m_PortalCooldownData;

	/** The number of ticks this entity has been alive for */
	long int m_TicksAlive;

	/** Handles the moving of this entity between worlds.
	Should handle degenerate cases such as moving to the same world. */
	void DoMoveToWorld(const sWorldChangeInfo & a_WorldChangeInfo);

	/** Applies friction to an entity
	@param a_Speed The speed vector to apply changes to
	@param a_SlowdownMultiplier The factor to reduce the speed by */
	static void ApplyFriction(Vector3d & a_Speed, double a_SlowdownMultiplier, float a_Dt);

	/** Called in each tick to handle air-related processing i.e. drowning */
	virtual void HandleAir(void);

	/** Called once per tick to set m_IsInFire, m_IsInLava, m_IsInWater and
	m_IsHeadInWater */
	virtual void SetSwimState(cChunk & a_Chunk);

	/** Set the entities position and last sent position.
	Only to be used when the caller will broadcast a teleport or equivalent to clients. */
	virtual void ResetPosition(Vector3d a_NewPos);

	/** If has any mobs are leashed, broadcasts every leashed entity to this. */
	void BroadcastLeashedMobs();

	/** Called when this entity dismounts from m_AttachedTo. */
	virtual void OnDetach();

private:

	/** Whether the entity is ticking or not. If not, it is scheduled for removal or world-teleportation. */
	bool m_IsTicking;

	/** The chunk which is responsible for ticking this entity. */
	cChunk * m_ParentChunk;

	/** Measured in degrees, [-180, +180) */
	double   m_HeadYaw;

	/** Measured in degrees, [-180, +180) */
	Vector3d m_Rot;

	/** Position of the entity's XZ center and Y bottom */
	Vector3d m_Position;

	/** Measured in meter / second */
	Vector3d m_WaterSpeed;

	/** Measured in Kilograms (Kg) */
	double m_Mass;

	/** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */
	float m_Width;

	/** Height of the entity (Y axis). */
	float m_Height;

	/** If a player hit a entity, the entity receive a invulnerable of 10 ticks.
	While this ticks, a player can't hit this entity. */
	int m_InvulnerableTicks;

	typedef std::list<cMonster *> cMonsterList;

	/** List of leashed mobs to this entity */
	cMonsterList m_LeashedMobs;

	/** List of players who are spectating this entity. */
	std::vector<cPlayer *> m_Spectators;
} ;  // tolua_export
