summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/Entities')
-rw-r--r--src/Entities/ArrowEntity.cpp4
-rw-r--r--src/Entities/Boat.cpp4
-rw-r--r--src/Entities/Entity.cpp39
-rw-r--r--src/Entities/Entity.h14
-rw-r--r--src/Entities/EntityEffect.cpp4
-rw-r--r--src/Entities/FallingBlock.cpp2
-rw-r--r--src/Entities/FireChargeEntity.cpp1
-rw-r--r--src/Entities/FireworkEntity.cpp2
-rw-r--r--src/Entities/Floater.cpp6
-rw-r--r--src/Entities/GhastFireballEntity.cpp1
-rw-r--r--src/Entities/HangingEntity.h7
-rw-r--r--src/Entities/Minecart.cpp8
-rw-r--r--src/Entities/Minecart.h7
-rw-r--r--src/Entities/Pawn.cpp2
-rw-r--r--src/Entities/Pickup.cpp3
-rw-r--r--src/Entities/Player.cpp192
-rw-r--r--src/Entities/Player.h194
-rw-r--r--src/Entities/ProjectileEntity.cpp14
-rw-r--r--src/Entities/ProjectileEntity.h2
-rw-r--r--src/Entities/TNTEntity.cpp4
-rw-r--r--src/Entities/WitherSkullEntity.cpp2
21 files changed, 317 insertions, 195 deletions
diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp
index 3c1fabb1b..32952100c 100644
--- a/src/Entities/ArrowEntity.cpp
+++ b/src/Entities/ArrowEntity.cpp
@@ -21,6 +21,8 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
{
SetSpeed(a_Speed);
SetMass(0.1);
+ SetGravity(-20.0f);
+ SetAirDrag(0.2f);
SetYawFromSpeed();
SetPitchFromSpeed();
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
@@ -48,6 +50,8 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
{
m_PickupState = psInCreative;
}
+ SetGravity(-20.0f);
+ SetAirDrag(0.01f);
}
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 6177eb32f..4ad418be4 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -16,7 +16,9 @@
cBoat::cBoat(double a_X, double a_Y, double a_Z) :
super(etBoat, a_X, a_Y, a_Z, 0.98, 0.7)
{
- SetMass(20.f);
+ SetMass(20.0f);
+ SetGravity(-16.0f);
+ SetAirDrag(0.05f);
SetMaxHealth(6);
SetHealth(6);
}
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index c8df6b4b1..dca44488b 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -36,6 +36,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
m_bHasSentNoSpeed(true),
m_bOnGround(false),
m_Gravity(-9.81f),
+ m_AirDrag(0.02f),
m_LastPos(a_X, a_Y, a_Z),
m_IsInitialized(false),
m_WorldTravellingFrom(nullptr),
@@ -246,7 +247,6 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
if (a_Attacker != nullptr)
{
Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 16 : 11);
- Heading.y = 1.6;
}
TDI.Knockback = Heading * a_KnockbackAmount;
@@ -943,6 +943,7 @@ void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
// Normal gravity
fallspeed = m_Gravity * DtSec.count();
+ NextSpeed -= NextSpeed * (m_AirDrag * 20.0f) * DtSec.count();
}
NextSpeed.y += static_cast<float>(fallspeed);
}
@@ -999,7 +1000,7 @@ void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
NextSpeed += m_WaterSpeed;
- if (NextSpeed.SqrLength() > 0.f)
+ if (NextSpeed.SqrLength() > 0.0f)
{
cTracer Tracer(GetWorld());
// Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse
@@ -1015,20 +1016,20 @@ void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
// Block hit was within our projected path
// Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1.
// For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP
- if (Tracer.HitNormal.x != 0.f)
+ if (Tracer.HitNormal.x != 0.0f)
{
- NextSpeed.x = 0.f;
+ NextSpeed.x = 0.0f;
}
- if (Tracer.HitNormal.y != 0.f)
+ if (Tracer.HitNormal.y != 0.0f)
{
- NextSpeed.y = 0.f;
+ NextSpeed.y = 0.0f;
}
- if (Tracer.HitNormal.z != 0.f)
+ if (Tracer.HitNormal.z != 0.0f)
{
- NextSpeed.z = 0.f;
+ NextSpeed.z = 0.0f;
}
- if (Tracer.HitNormal.y == 1.f) // Hit BLOCK_FACE_YP, we are on the ground
+ if (Tracer.HitNormal.y == 1.0f) // Hit BLOCK_FACE_YP, we are on the ground
{
m_bOnGround = true;
}
@@ -1308,7 +1309,8 @@ bool cEntity::DetectPortal()
if (IsPlayer())
{
- ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); // Send a respawn packet before world is loaded/generated so the client isn't left in limbo
+ // Send a respawn packet before world is loaded / generated so the client isn't left in limbo
+ ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld);
}
return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false);
@@ -1401,14 +1403,25 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
return false;
}
+ // Ask the plugins if the entity is allowed to changing the world
+ if (cRoot::Get()->GetPluginManager()->CallHookEntityChangingWorld(*this, *a_World))
+ {
+ // A Plugin doesn't allow the entity to changing the world
+ return false;
+ }
+
// Remove all links to the old world
SetWorldTravellingFrom(GetWorld()); // cChunk::Tick() handles entity removal
GetWorld()->BroadcastDestroyEntity(*this);
// Queue add to new world
a_World->AddEntity(this);
+ cWorld * OldWorld = cRoot::Get()->GetWorld(GetWorld()->GetName()); // Required for the hook HOOK_ENTITY_CHANGED_WORLD
SetWorld(a_World);
+ // Entity changed the world, call the hook
+ cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, *OldWorld);
+
return true;
}
@@ -1687,8 +1700,8 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude);
}
- // Clients seem to store two positions, one for the velocity packet and one for the teleport/relmove packet
- // The latter is only changed with a relmove/teleport, and m_LastPos stores this position
+ // Clients seem to store two positions, one for the velocity packet and one for the teleport / relmove packet
+ // The latter is only changed with a relmove / teleport, and m_LastPos stores this position
m_LastPos = GetPosition();
}
else
@@ -1971,7 +1984,7 @@ void cEntity::SteerVehicle(float a_Forward, float a_Sideways)
{
return;
}
- if ((a_Forward != 0.f) || (a_Sideways != 0.f))
+ if ((a_Forward != 0.0f) || (a_Sideways != 0.0f))
{
m_AttachedTo->HandleSpeedFromAttachee(a_Forward, a_Sideways);
}
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 9bb1837f1..fecbb9bf5 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -270,6 +270,10 @@ public:
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);
@@ -470,7 +474,7 @@ protected:
static cCriticalSection m_CSCount;
static UInt32 m_EntityCount;
- /** Measured in meter/second (m/s) */
+ /** 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.
@@ -490,7 +494,7 @@ protected:
/** Stores whether head yaw has been set manually */
bool m_bDirtyHead;
- /** Stores whether our yaw/pitch/roll (body orientation) has been set manually */
+ /** 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
@@ -504,6 +508,12 @@ protected:
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: http://minecraft.gamepedia.com/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_LastPos;
diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp
index bae686b77..c8be414d4 100644
--- a/src/Entities/EntityEffect.cpp
+++ b/src/Entities/EntityEffect.cpp
@@ -102,11 +102,11 @@ int cEntityEffect::GetPotionEffectDuration(short a_ItemDamage)
// If potion is level II, half the duration. If not, stays the same
TierCoeff = (GetPotionEffectIntensity(a_ItemDamage) > 0) ? 0.5 : 1;
- // If potion is extended, multiply duration by 8/3. If not, stays the same
+ // If potion is extended, multiply duration by 8 / 3. If not, stays the same
// Extended potion if sixth lowest bit is set
ExtCoeff = (a_ItemDamage & 0x40) ? (8.0 / 3.0) : 1;
- // If potion is splash potion, multiply duration by 3/4. If not, stays the same
+ // If potion is splash potion, multiply duration by 3 / 4. If not, stays the same
SplashCoeff = IsPotionDrinkable(a_ItemDamage) ? 1 : 0.75;
// Ref.:
diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index 7301a3c9d..4a165909a 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -16,6 +16,8 @@ cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_Block
m_BlockMeta(a_BlockMeta),
m_OriginalPosition(a_BlockPosition)
{
+ SetGravity(-16.0f);
+ SetAirDrag(0.02f);
}
diff --git a/src/Entities/FireChargeEntity.cpp b/src/Entities/FireChargeEntity.cpp
index aba32602f..f6c665156 100644
--- a/src/Entities/FireChargeEntity.cpp
+++ b/src/Entities/FireChargeEntity.cpp
@@ -12,6 +12,7 @@ cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y
{
SetSpeed(a_Speed);
SetGravity(0);
+ SetAirDrag(0);
}
diff --git a/src/Entities/FireworkEntity.cpp b/src/Entities/FireworkEntity.cpp
index 32eaf669a..89f69f113 100644
--- a/src/Entities/FireworkEntity.cpp
+++ b/src/Entities/FireworkEntity.cpp
@@ -13,6 +13,8 @@ cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, do
m_TicksToExplosion(a_Item.m_FireworkItem.m_FlightTimeInTicks),
m_FireworkItem(a_Item)
{
+ SetGravity(0);
+ SetAirDrag(0);
}
diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp
index cf8dd6c6f..0c868270d 100644
--- a/src/Entities/Floater.cpp
+++ b/src/Entities/Floater.cpp
@@ -6,7 +6,7 @@
#include "Floater.h"
#include "Player.h"
#include "../ClientHandle.h"
-
+#include "Broadcaster.h"
@@ -145,12 +145,12 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
LOGD("Started producing particles for floater %i", GetUniqueID());
m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8)));
- m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
+ m_World->GetBroadcaster().BroadcastParticleEffect("splash", static_cast<Vector3f>(m_ParticlePos), Vector3f{}, 0, 15);
}
else if (m_CountDownTime < 20)
{
m_ParticlePos = (m_ParticlePos + (GetPosition() - m_ParticlePos) / 6);
- m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
+ m_World->GetBroadcaster().BroadcastParticleEffect("splash", static_cast<Vector3f>(m_ParticlePos), Vector3f{}, 0, 15);
}
m_CountDownTime--;
diff --git a/src/Entities/GhastFireballEntity.cpp b/src/Entities/GhastFireballEntity.cpp
index 9e4cb387e..c64fb2a17 100644
--- a/src/Entities/GhastFireballEntity.cpp
+++ b/src/Entities/GhastFireballEntity.cpp
@@ -12,6 +12,7 @@ cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, doub
{
SetSpeed(a_Speed);
SetGravity(0);
+ SetAirDrag(0);
}
diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h
index 507502ac6..9d783006c 100644
--- a/src/Entities/HangingEntity.h
+++ b/src/Entities/HangingEntity.h
@@ -27,7 +27,10 @@ public:
eBlockFace GetFacing() const { return cHangingEntity::ProtocolFaceToBlockFace(m_Facing); }
/** Set the direction in which the entity is facing. */
- void SetFacing(eBlockFace a_Facing) { m_Facing = cHangingEntity::BlockFaceToProtocolFace(a_Facing); }
+ void SetFacing(eBlockFace a_Facing)
+ {
+ m_Facing = cHangingEntity::BlockFaceToProtocolFace(a_Facing);
+ }
// tolua_end
@@ -37,7 +40,7 @@ public:
/** Set the direction in which the entity is facing. */
void SetProtocolFacing(Byte a_Facing)
{
- ASSERT((a_Facing <= 3) && (a_Facing >= 0));
+ ASSERT(a_Facing <= 3);
m_Facing = a_Facing;
}
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index ee10cf6b3..b80759d24 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -92,7 +92,9 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
m_DetectorRailPosition(0, 0, 0),
m_bIsOnDetectorRail(false)
{
- SetMass(20.f);
+ SetMass(20.0f);
+ SetGravity(-16.0f);
+ SetAirDrag(0.05f);
SetMaxHealth(6);
SetHealth(6);
SetWidth(1);
@@ -903,7 +905,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
}
/* Check to which side the minecart is to be pushed.
- Let's consider a z-x-coordinate system where the minecart is the center (0/0).
+ Let's consider a z-x-coordinate system where the minecart is the center (0, 0).
The minecart moves along the line x = -z, the perpendicular line to this is x = z.
In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */
if (
@@ -952,7 +954,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
}
/* Check to which side the minecart is to be pushed.
- Let's consider a z-x-coordinate system where the minecart is the center (0/0).
+ Let's consider a z-x-coordinate system where the minecart is the center (0, 0).
The minecart moves along the line x = z, the perpendicular line to this is x = -z.
In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */
if (
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 898776e71..05eaf16e9 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -29,7 +29,7 @@ public:
enum ePayload
{
mpNone = 0, // Empty minecart, ridable by player or mobs
- mpChest = 1, // Minecart-with-chest, can store a grid of 3*8 items
+ mpChest = 1, // Minecart-with-chest, can store a grid of 3 * 8 items
mpFurnace = 2, // Minecart-with-furnace, can be powered
mpTNT = 3, // Minecart-with-TNT, can be blown up with activator rail
mpHopper = 5, // Minecart-with-hopper, can be hopper
@@ -54,8 +54,7 @@ protected:
cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z);
/** Handles physics on normal rails
- For each tick, slow down on flat rails, speed up or slow down on ascending/descending rails (depending on direction), and turn on curved rails
- */
+ For each tick, slow down on flat rails, speed up or slow down on ascending / descending rails (depending on direction), and turn on curved rails. */
void HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
/** Handles powered rail physics
@@ -136,7 +135,7 @@ protected:
virtual void Destroyed() override;
// cItemGrid::cListener overrides:
- virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum)
+ virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override
{
UNUSED(a_SlotNum);
ASSERT(a_Grid == &m_Contents);
diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp
index baf8a2f3b..fcb686e28 100644
--- a/src/Entities/Pawn.cpp
+++ b/src/Entities/Pawn.cpp
@@ -13,6 +13,8 @@ cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height) :
super(a_EntityType, 0, 0, 0, a_Width, a_Height)
, m_EntityEffects(tEffectMap())
{
+ SetGravity(-32.0f);
+ SetAirDrag(0.02f);
}
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index 9f2609894..f2f76dbf9 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -91,7 +91,8 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_It
, m_bCollected(false)
, m_bIsPlayerCreated(IsPlayerCreated)
{
- SetGravity(-10.5f);
+ SetGravity(-16.0f);
+ SetAirDrag(0.02f);
SetMaxHealth(5);
SetHealth(5);
SetSpeed(a_SpeedX, a_SpeedY, a_SpeedZ);
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index c89e7b87c..e3e3fac4f 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -94,7 +94,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
SetMaxHealth(MAX_HEALTH);
m_Health = MAX_HEALTH;
-
+
m_LastPlayerListTime = std::chrono::steady_clock::now();
m_PlayerName = a_PlayerName;
@@ -106,7 +106,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
SetPosY(World->GetSpawnY());
SetPosZ(World->GetSpawnZ());
SetBedPos(Vector3i(static_cast<int>(World->GetSpawnX()), static_cast<int>(World->GetSpawnY()), static_cast<int>(World->GetSpawnZ())));
-
+
LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}",
a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ()
);
@@ -128,7 +128,14 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
m_IsFlying = true;
}
}
-
+
+ if (m_GameMode == gmSpectator) // If player is reconnecting to the server in spectator mode
+ {
+ m_CanFly = true;
+ m_IsFlying = true;
+ m_bVisible = false;
+ }
+
cRoot::Get()->GetServer()->PlayerCreated(this);
}
@@ -145,17 +152,17 @@ cPlayer::~cPlayer(void)
}
LOGD("Deleting cPlayer \"%s\" at %p, ID %d", GetName().c_str(), this, GetUniqueID());
-
+
// Notify the server that the player is being destroyed
cRoot::Get()->GetServer()->PlayerDestroying(this);
SaveToDisk();
m_ClientHandle = nullptr;
-
+
delete m_InventoryWindow;
m_InventoryWindow = nullptr;
-
+
LOGD("Player %p deleted", this);
}
@@ -201,7 +208,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
m_ClientHandle = nullptr;
return;
}
-
+
if (!m_ClientHandle->IsPlaying())
{
// We're not yet in the game, ignore everything
@@ -210,21 +217,21 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
}
m_Stats.AddValue(statMinutesPlayed, 1);
-
+
if (!a_Chunk.IsValid())
{
// This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
return;
}
-
+
super::Tick(a_Dt, a_Chunk);
-
+
// Handle charging the bow:
if (m_IsChargingBow)
{
m_BowCharge += 1;
}
-
+
// Handle updating experience
if (m_bDirtyExperience)
{
@@ -236,7 +243,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
// Apply food exhaustion from movement:
ApplyFoodExhaustionFromMovement();
-
+
if (cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this, m_LastPos, GetPosition()))
{
CanMove = false;
@@ -257,10 +264,10 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
FinishEating();
}
-
+
HandleFood();
}
-
+
if (m_IsFishing)
{
HandleFloater();
@@ -355,7 +362,7 @@ float cPlayer::GetXpPercentage()
int currentLevel_XpBase = XpForLevel(currentLevel);
return static_cast<float>(m_CurrentXp - currentLevel_XpBase) /
- static_cast<float>(XpForLevel(1+currentLevel) - currentLevel_XpBase);
+ static_cast<float>(XpForLevel(1 + currentLevel) - currentLevel_XpBase);
}
@@ -364,7 +371,7 @@ float cPlayer::GetXpPercentage()
bool cPlayer::SetCurrentExperience(int a_CurrentXp)
{
- if (!(a_CurrentXp >= 0) || (a_CurrentXp > (std::numeric_limits<int>().max() - m_LifetimeTotalXp)))
+ if (!(a_CurrentXp >= 0) || (a_CurrentXp > (std::numeric_limits<int>::max() - m_LifetimeTotalXp)))
{
LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_CurrentXp);
return false; // oops, they gave us a dodgey number
@@ -403,7 +410,7 @@ int cPlayer::DeltaExperience(int a_Xp_delta)
m_LifetimeTotalXp += a_Xp_delta;
}
- LOGD("Player \"%s\" gained/lost %d experience, total is now: %d", GetName().c_str(), a_Xp_delta, m_CurrentXp);
+ LOGD("Player \"%s\" gained / lost %d experience, total is now: %d", GetName().c_str(), a_Xp_delta, m_CurrentXp);
// Set experience to be updated
m_bDirtyExperience = true;
@@ -460,7 +467,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
{
return;
}
-
+
m_bTouchGround = a_bTouchGround;
if (!m_bTouchGround)
@@ -509,7 +516,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
{
// cPlayer makes sure damage isn't applied in creative, no need to check here
TakeDamage(dtFalling, nullptr, Damage, Damage, 0);
-
+
// Fall particles
GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, static_cast<int>(GetPosY()) - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
}
@@ -541,7 +548,7 @@ void cPlayer::SetFoodLevel(int a_FoodLevel)
m_FoodSaturationLevel = 5.0;
return;
}
-
+
m_FoodLevel = FoodLevel;
SendHealth();
}
@@ -609,7 +616,7 @@ void cPlayer::StartEating(void)
{
// Set the timer:
m_EatingFinishTick = m_World->GetWorldAge() + EATING_TICKS;
-
+
// Send the packets:
m_World->BroadcastEntityAnimation(*this, 3);
m_World->BroadcastEntityMetadata(*this);
@@ -623,7 +630,7 @@ void cPlayer::FinishEating(void)
{
// Reset the timer:
m_EatingFinishTick = -1;
-
+
// Send the packets:
m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
m_World->BroadcastEntityMetadata(*this);
@@ -757,7 +764,7 @@ void cPlayer::SetSprintingMaxSpeed(double a_Speed)
void cPlayer::SetFlyingMaxSpeed(double a_Speed)
{
m_FlyingMaxSpeed = a_Speed;
-
+
// Update the flying speed, always:
m_ClientHandle->SendPlayerAbilities();
}
@@ -769,7 +776,7 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed)
void cPlayer::SetCrouch(bool a_IsCrouched)
{
// Set the crouch status, broadcast to all visible players
-
+
if (a_IsCrouched == m_IsCrouched)
{
// No change
@@ -790,7 +797,7 @@ void cPlayer::SetSprint(bool a_IsSprinting)
// No change
return;
}
-
+
m_IsSprinting = a_IsSprinting;
m_ClientHandle->SendPlayerMaxSpeed();
}
@@ -876,7 +883,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
}
}
}
-
+
if (super::DoTakeDamage(a_TDI))
{
// Any kind of damage adds food exhaustion
@@ -1005,7 +1012,7 @@ void cPlayer::Respawn(void)
m_Health = GetMaxHealth();
SetInvulnerableTicks(20);
-
+
// Reset food level:
m_FoodLevel = MAX_FOOD_LEVEL;
m_FoodSaturationLevel = 5.0;
@@ -1017,7 +1024,7 @@ void cPlayer::Respawn(void)
// ToDo: send score to client? How?
m_ClientHandle->SendRespawn(GetWorld()->GetDimension(), true);
-
+
// Extinguish the fire:
StopBurning();
@@ -1151,7 +1158,7 @@ void cPlayer::CloseWindow(bool a_CanRefuse)
m_CurrentWindow = m_InventoryWindow;
return;
}
-
+
if (m_CurrentWindow->ClosedByPlayer(*this, a_CanRefuse) || !a_CanRefuse)
{
// Close accepted, go back to inventory window (the default):
@@ -1189,21 +1196,17 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
LOGWARNING("%s: Setting invalid gamemode: %d", GetName().c_str(), a_GameMode);
return;
}
-
+
if (m_GameMode == a_GameMode)
{
// Gamemode already set
return;
}
-
+
m_GameMode = a_GameMode;
m_ClientHandle->SendGameMode(a_GameMode);
- if (!(IsGameModeCreative() || IsGameModeSpectator()))
- {
- SetFlying(false);
- SetCanFly(false);
- }
+ SetCapabilities();
m_World->BroadcastPlayerListUpdateGameMode(*this);
}
@@ -1215,6 +1218,30 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
void cPlayer::LoginSetGameMode( eGameMode a_GameMode)
{
m_GameMode = a_GameMode;
+
+ SetCapabilities();
+}
+
+
+
+
+
+void cPlayer::SetCapabilities()
+{
+ if (!IsGameModeCreative() || IsGameModeSpectator())
+ {
+ SetFlying(false);
+ SetCanFly(false);
+ }
+
+ if (IsGameModeSpectator())
+ {
+ SetVisible(false);
+ }
+ else
+ {
+ SetVisible(true);
+ }
}
@@ -1306,12 +1333,12 @@ void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees)
Vector3d cPlayer::GetThrowStartPos(void) const
{
Vector3d res = GetEyePosition();
-
+
// Adjust the position to be just outside the player's bounding box:
res.x += 0.16 * cos(GetPitch());
res.y += -0.1;
res.z += 0.16 * sin(GetPitch());
-
+
return res;
}
@@ -1323,9 +1350,9 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
{
Vector3d res = GetLookVector();
res.Normalize();
-
+
// TODO: Add a slight random change (+-0.0075 in each direction)
-
+
return res * a_SpeedCoeff;
}
@@ -1370,13 +1397,13 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos)
}
return;
}
-
+
// TODO: should do some checks to see if player is not moving through terrain
// TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
Vector3d DeltaPos = a_NewPos - GetPosition();
UpdateMovementStats(DeltaPos);
-
+
SetPosition( a_NewPos);
SetStance(a_NewPos.y + 1.62);
}
@@ -1411,17 +1438,26 @@ bool cPlayer::HasPermission(const AString & a_Permission)
// Empty permission request is always granted
return true;
}
-
+
AStringVector Split = StringSplit(a_Permission, ".");
+ // Iterate over all restrictions; if any matches, then return failure:
+ for (auto & Restriction: m_SplitRestrictions)
+ {
+ if (PermissionMatches(Split, Restriction))
+ {
+ return false;
+ }
+ } // for Restriction - m_SplitRestrictions[]
+
// Iterate over all granted permissions; if any matches, then return success:
- for (AStringVectorVector::const_iterator itr = m_SplitPermissions.begin(), end = m_SplitPermissions.end(); itr != end; ++itr)
+ for (auto & Permission: m_SplitPermissions)
{
- if (PermissionMatches(Split, *itr))
+ if (PermissionMatches(Split, Permission))
{
return true;
}
- } // for itr - m_SplitPermissions[]
+ } // for Permission - m_SplitPermissions[]
// No granted permission matches
return false;
@@ -1574,7 +1610,7 @@ void cPlayer::TossItems(const cItems & a_Items)
{
return;
}
-
+
m_Stats.AddValue(statItemsDropped, (StatValue)a_Items.Size());
double vX = 0, vY = 0, vZ = 0;
@@ -1596,19 +1632,30 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
// Don't move to same world
return false;
}
-
+
+ // Ask the plugins if the player is allowed to changing the world
+ if (cRoot::Get()->GetPluginManager()->CallHookEntityChangingWorld(*this, *a_World))
+ {
+ // A Plugin doesn't allow the player to changing the world
+ return false;
+ }
+
// Send the respawn packet:
if (a_ShouldSendRespawn && (m_ClientHandle != nullptr))
{
m_ClientHandle->SendRespawn(a_World->GetDimension());
}
+ // Broadcast for other people that the player is gone.
+ GetWorld()->BroadcastDestroyEntity(*this);
+
// Remove player from the old world
SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal
GetWorld()->RemovePlayer(this, false);
// Queue adding player to the new world, including all the necessary adjustments to the object
a_World->AddPlayer(this);
+ cWorld * OldWorld = cRoot::Get()->GetWorld(GetWorld()->GetName()); // Required for the hook HOOK_ENTITY_CHANGED_WORLD
SetWorld(a_World); // Chunks may be streamed before cWorld::AddPlayer() sets the world to the new value
// Update the view distance.
@@ -1619,7 +1666,13 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
{
m_ClientHandle->SendWeather(a_World->GetWeather());
}
-
+
+ // Broadcast the player into the new world.
+ a_World->BroadcastSpawnEntity(*this);
+
+ // Player changed the world, call the hook
+ cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, *OldWorld);
+
return true;
}
@@ -1636,7 +1689,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
{
return true;
}
-
+
// Load from the offline UUID file, if allowed:
AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName());
const char * OfflineUsage = " (unused)";
@@ -1648,7 +1701,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
return true;
}
}
-
+
// Load from the old-style name-based file, if allowed:
if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData())
{
@@ -1663,7 +1716,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
return true;
}
}
-
+
// None of the files loaded successfully
LOG("Player data file not found for %s (%s, offline %s%s), will be reset to defaults.",
GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str(), OfflineUsage
@@ -1740,7 +1793,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
{
m_CanFly = true;
}
-
+
m_Inventory.LoadFromJson(root["inventory"]);
cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents);
@@ -1756,14 +1809,14 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
m_LastBedPos.z = root.get("SpawnZ", a_World->GetSpawnZ()).asInt();
// Load the player stats.
- // We use the default world name (like bukkit) because stats are shared between dimensions/worlds.
+ // We use the default world name (like bukkit) because stats are shared between dimensions / worlds.
cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats);
StatSerializer.Load();
-
+
LOGD("Player %s was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), a_World->GetName().c_str()
);
-
+
return true;
}
@@ -1853,7 +1906,7 @@ bool cPlayer::SaveToDisk()
}
// Save the player stats.
- // We use the default world name (like bukkit) because stats are shared between dimensions/worlds.
+ // We use the default world name (like bukkit) because stats are shared between dimensions / worlds.
cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats);
if (!StatSerializer.Save())
{
@@ -2061,7 +2114,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
}
else
{
- if (Value >= 25) // Ignore small/slow movement
+ if (Value >= 25) // Ignore small / slow movement
{
m_Stats.AddValue(statDistFlown, Value);
}
@@ -2119,7 +2172,7 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
{
return;
}
-
+
// Calculate the distance travelled, update the last pos:
Vector3d Movement(GetPosition() - m_LastPos);
Movement.y = 0; // Only take XZ movement into account
@@ -2163,15 +2216,24 @@ void cPlayer::LoadRank(void)
RankMgr->UpdatePlayerName(m_UUID, m_PlayerName);
}
m_Permissions = RankMgr->GetPlayerPermissions(m_UUID);
+ m_Restrictions = RankMgr->GetPlayerRestrictions(m_UUID);
RankMgr->GetRankVisuals(m_Rank, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode);
// Break up the individual permissions on each dot, into m_SplitPermissions:
m_SplitPermissions.clear();
m_SplitPermissions.reserve(m_Permissions.size());
- for (AStringVector::const_iterator itr = m_Permissions.begin(), end = m_Permissions.end(); itr != end; ++itr)
+ for (auto & Permission: m_Permissions)
+ {
+ m_SplitPermissions.push_back(StringSplit(Permission, "."));
+ } // for Permission - m_Permissions[]
+
+ // Break up the individual restrictions on each dot, into m_SplitRestrictions:
+ m_SplitRestrictions.clear();
+ m_SplitRestrictions.reserve(m_Restrictions.size());
+ for (auto & Restriction: m_Restrictions)
{
- m_SplitPermissions.push_back(StringSplit(*itr, "."));
- } // for itr - m_Permissions[]
+ m_SplitRestrictions.push_back(StringSplit(Restriction, "."));
+ } // for itr - m_Restrictions[]
}
@@ -2313,7 +2375,7 @@ AString cPlayer::GetUUIDFileName(const AString & a_UUID)
{
AString UUID = cMojangAPI::MakeUUIDDashed(a_UUID);
ASSERT(UUID.length() == 36);
-
+
AString res("players/");
res.append(UUID, 0, 2);
res.push_back('/');
@@ -2321,7 +2383,3 @@ AString cPlayer::GetUUIDFileName(const AString & a_UUID)
res.append(".json");
return res;
}
-
-
-
-
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 3dae58dc1..a84fdd0c7 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -26,42 +26,42 @@ class cPlayer :
public cPawn
{
typedef cPawn super;
-
+
public:
static const int MAX_HEALTH;
-
+
static const int MAX_FOOD_LEVEL;
-
+
/** Number of ticks it takes to eat an item */
static const int EATING_TICKS;
-
+
// tolua_end
-
+
CLASS_PROTODEF(cPlayer)
-
+
cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName);
-
+
virtual ~cPlayer();
virtual void SpawnOn(cClientHandle & a_Client) override;
-
+
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); }
/** Returns the curently equipped weapon; empty item if none */
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
-
+
/** Returns the currently equipped helmet; empty item if none */
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
-
+
/** Returns the currently equipped chestplate; empty item if none */
virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); }
/** Returns the currently equipped leggings; empty item if none */
virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); }
-
+
/** Returns the currently equipped boots; empty item if none */
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
@@ -104,16 +104,16 @@ public:
static int CalcLevelFromXp(int a_CurrentXp);
// tolua_end
-
+
/** Starts charging the equipped bow */
void StartChargingBow(void);
-
+
/** Finishes charging the current bow. Returns the number of ticks for which the bow has been charged */
int FinishChargingBow(void);
-
+
/** Cancels the current bow charging */
void CancelChargingBow(void);
-
+
/** Returns true if the player is currently charging the bow */
bool IsChargingBow(void) const { return m_IsChargingBow; }
@@ -122,13 +122,13 @@ public:
double GetEyeHeight(void) const; // tolua_export
Vector3d GetEyePosition(void) const; // tolua_export
virtual bool IsOnGround(void) const override { return m_bTouchGround; }
- inline double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
+ inline double GetStance(void) const { return m_Stance; } // tolua_export
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
inline const cInventory & GetInventory(void) const { return m_Inventory; }
/** Gets the contents of the player's associated enderchest */
cItemGrid & GetEnderChestContents(void) { return m_EnderChestContents; }
-
+
inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export
/** Returns whether the player is climbing (ladders, vines etc.) */
@@ -137,43 +137,49 @@ public:
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
// tolua_begin
-
+
/** Sends the "look" packet to the player, forcing them to set their rotation to the specified values.
a_YawDegrees is clipped to range [-180, +180),
a_PitchDegrees is clipped to range [-180, +180) but the client only uses [-90, +90]
*/
void SendRotation(double a_YawDegrees, double a_PitchDegrees);
-
+
/** Returns the position where projectiles thrown by this player should start, player eye position + adjustment */
Vector3d GetThrowStartPos(void) const;
-
+
/** Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. */
Vector3d GetThrowSpeed(double a_SpeedCoeff) const;
-
+
/** Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */
eGameMode GetGameMode(void) const { return m_GameMode; }
-
+
/** Returns the current effective gamemode (inherited gamemode is resolved before returning) */
eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; }
-
+
/** Sets the gamemode for the player.
The gamemode may be gmNotSet, in that case the player inherits the world's gamemode.
Updates the gamemode on the client (sends the packet)
*/
void SetGameMode(eGameMode a_GameMode);
+ // Sets the current gamemode, doesn't check validity, doesn't send update packets to client
+ void LoginSetGameMode(eGameMode a_GameMode);
+
+ // Updates player's capabilities - flying, visibility, etc. from their gamemode.
+ void SetCapabilities();
+
/** Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world */
bool IsGameModeCreative(void) const;
-
+
/** Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world */
bool IsGameModeSurvival(void) const;
-
+
/** Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world */
bool IsGameModeAdventure(void) const;
-
+
/** Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current world */
bool IsGameModeSpectator(void) const;
-
+
AString GetIP(void) const { return m_IP; } // tolua_export
/** Returns the associated team, nullptr if none */
@@ -195,11 +201,8 @@ public:
If the achievement has been already awarded to the player, this method will just increment the stat counter.
Returns the _new_ stat value. (0 = Could not award achievement) */
unsigned int AwardAchievement(const eStatistic a_Ach);
-
+
void SetIP(const AString & a_IP);
-
- // Sets the current gamemode, doesn't check validity, doesn't send update packets to client
- void LoginSetGameMode(eGameMode a_GameMode);
/** Forces the player to move in the given direction.
@deprecated Use SetSpeed instead. */
@@ -210,15 +213,15 @@ public:
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
-
+
/** Opens the specified window; closes the current one first using CloseWindow() */
void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
-
+
// tolua_begin
-
+
/** Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true */
void CloseWindow(bool a_CanRefuse = true);
-
+
/** Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow */
void CloseWindowIfID(char a_WindowID, bool a_CanRefuse = true);
@@ -243,7 +246,7 @@ public:
const AString & GetName(void) const { return m_PlayerName; }
void SetName(const AString & a_Name) { m_PlayerName = a_Name; }
-
+
// tolua_end
bool HasPermission(const AString & a_Permission); // tolua_export
@@ -254,10 +257,13 @@ public:
static bool PermissionMatches(const AStringVector & a_Permission, const AStringVector & a_Template); // Exported in ManualBindings with AString params
/** Returns all the permissions that the player has assigned to them. */
- const AStringVector & GetPermissions(void) { return m_Permissions; } // Exported in ManualBindings.cpp
+ const AStringVector & GetPermissions(void) const { return m_Permissions; } // Exported in ManualBindings.cpp
+
+ /** Returns all the restrictions that the player has assigned to them. */
+ const AStringVector & GetRestrictions(void) const { return m_Restrictions; } // Exported in ManualBindings.cpp
// tolua_begin
-
+
/** Returns the full color code to use for this player, based on their rank.
The returned value either is empty, or includes the cChatColor::Delimiter. */
AString GetColor(void) const;
@@ -276,15 +282,15 @@ public:
/** Heals the player by the specified amount of HPs (positive only); sends health update */
virtual void Heal(int a_Health) override;
-
+
int GetFoodLevel (void) const { return m_FoodLevel; }
double GetFoodSaturationLevel (void) const { return m_FoodSaturationLevel; }
int GetFoodTickTimer (void) const { return m_FoodTickTimer; }
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
-
+
/** Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore */
bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
-
+
void SetFoodLevel (int a_FoodLevel);
void SetFoodSaturationLevel (double a_FoodSaturationLevel);
void SetFoodTickTimer (int a_FoodTickTimer);
@@ -295,10 +301,10 @@ public:
/** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */
void AddFoodExhaustion(double a_Exhaustion);
-
+
/** Returns true if the player is currently in the process of eating the currently equipped item */
bool IsEating(void) const { return (m_EatingFinishTick >= 0); }
-
+
/** Returns true if the player is currently flying. */
bool IsFlying(void) const { return m_IsFlying; }
@@ -326,16 +332,16 @@ public:
GetWorld()->BroadcastEntityAnimation(*this, 2);
}
}
-
+
/** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
void StartEating(void);
-
+
/** Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets */
void FinishEating(void);
-
+
/** Aborts the current eating operation */
void AbortEating(void);
-
+
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
virtual void Killed(cEntity * a_Victim) override;
@@ -353,69 +359,69 @@ public:
bool SaveToDisk(void);
typedef cWorld * cWorldPtr;
-
+
/** Loads the player data from the disk file
Sets a_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile()
Returns true on success, false on failure
*/
bool LoadFromDisk(cWorldPtr & a_World);
-
+
/** Loads the player data from the specified file
Sets a_World to the world where the player will spawn, based on the stored world name or the default world
Returns true on success, false on failure
*/
bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World);
-
+
const AString & GetLoadedWorldName() { return m_LoadedWorldName; }
void UseEquippedItem(int a_Amount = 1);
-
+
void SendHealth(void);
void SendExperience(void);
-
+
/** In UI windows, get the item that the player is dragging */
cItem & GetDraggingItem(void) {return m_DraggingItem; }
-
+
// In UI windows, when inventory-painting:
/** Clears the list of slots that are being inventory-painted. To be used by cWindow only */
void ClearInventoryPaintSlots(void);
-
+
/** Adds a slot to the list for inventory painting. To be used by cWindow only */
void AddInventoryPaintSlot(int a_SlotNum);
-
+
/** Returns the list of slots currently stored for inventory painting. To be used by cWindow only */
const cSlotNums & GetInventoryPaintSlots(void) const;
-
+
// tolua_begin
-
+
/** Returns the current relative maximum speed (takes current sprinting / flying state into account) */
double GetMaxSpeed(void) const;
-
+
/** Gets the normal relative maximum speed */
double GetNormalMaxSpeed(void) const { return m_NormalMaxSpeed; }
-
+
/** Gets the sprinting relative maximum speed */
double GetSprintingMaxSpeed(void) const { return m_SprintingMaxSpeed; }
-
+
/** Gets the flying relative maximum speed */
double GetFlyingMaxSpeed(void) const { return m_FlyingMaxSpeed; }
-
+
/** Sets the normal relative maximum speed. Sends the update to player, if needed. */
void SetNormalMaxSpeed(double a_Speed);
-
+
/** Sets the sprinting relative maximum speed. Sends the update to player, if needed. */
void SetSprintingMaxSpeed(double a_Speed);
-
+
/** Sets the flying relative maximum speed. Sends the update to player, if needed. */
void SetFlyingMaxSpeed(double a_Speed);
-
+
/** Sets the crouch status, broadcasts to all visible players */
void SetCrouch(bool a_IsCrouched);
-
+
/** Starts or stops sprinting, sends the max speed update to the client, if needed */
void SetSprint(bool a_IsSprinting);
-
+
/** Flags the player as flying */
void SetFlying(bool a_IsFlying);
@@ -439,17 +445,17 @@ public:
/** Sets the player's bed (home) position */
void SetBedPos(const Vector3i & a_Pos) { m_LastBedPos = a_Pos; }
-
+
// tolua_end
/** Update movement-related statistics. */
void UpdateMovementStats(const Vector3d & a_DeltaPos);
-
+
// tolua_begin
/** Returns wheter the player can fly or not. */
virtual bool CanFly(void) const { return m_CanFly; }
-
+
/** Returns the UUID (short format) that has been read from the client, or empty string if not available. */
const AString & GetUUID(void) const { return m_UUID; }
@@ -480,16 +486,16 @@ public:
bool PlaceBlocks(const sSetBlockVector & a_Blocks);
// cEntity overrides:
- virtual bool IsCrouched (void) const { return m_IsCrouched; }
- virtual bool IsSprinting(void) const { return m_IsSprinting; }
- virtual bool IsRclking (void) const { return IsEating() || IsChargingBow(); }
+ virtual bool IsCrouched (void) const override { return m_IsCrouched; }
+ virtual bool IsSprinting(void) const override { return m_IsSprinting; }
+ virtual bool IsRclking (void) const override { return IsEating() || IsChargingBow(); }
- virtual void Detach(void);
+ virtual void Detach(void) override;
/** Called by cClientHandle when the client is being destroyed.
The player removes its m_ClientHandle ownership so that the ClientHandle gets deleted. */
void RemoveClientHandle(void);
-
+
protected:
typedef std::vector<std::vector<AString> > AStringVectorVector;
@@ -500,10 +506,18 @@ protected:
/** All the permissions that this player has, based on their rank. */
AStringVector m_Permissions;
+ /** All the restrictions that this player has, based on their rank. */
+ AStringVector m_Restrictions;
+
/** All the permissions that this player has, based on their rank, split into individual dot-delimited parts.
This is used mainly by the HasPermission() function to optimize the lookup. */
AStringVectorVector m_SplitPermissions;
+ /** All the restrictions that this player has, based on their rank, split into individual dot-delimited parts.
+ This is used mainly by the HasPermission() function to optimize the lookup. */
+ AStringVectorVector m_SplitRestrictions;
+
+
// Message visuals:
AString m_MsgPrefix, m_MsgSuffix;
AString m_MsgNameColorCode;
@@ -524,16 +538,16 @@ protected:
// Food-related variables:
/** Represents the food bar, one point equals half a "drumstick" */
int m_FoodLevel;
-
+
/** "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel */
double m_FoodSaturationLevel;
-
+
/** Count-up to the healing or damaging action, based on m_FoodLevel */
int m_FoodTickTimer;
-
+
/** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */
double m_FoodExhaustionLevel;
-
+
float m_LastJumpHeight;
float m_LastGroundHeight;
bool m_bTouchGround;
@@ -553,31 +567,31 @@ protected:
eGameMode m_GameMode;
AString m_IP;
-
+
/** The item being dragged by the cursor while in a UI window */
cItem m_DraggingItem;
std::chrono::steady_clock::time_point m_LastPlayerListTime;
cClientHandlePtr m_ClientHandle;
-
+
cSlotNums m_InventoryPaintSlots;
-
+
/** Max speed, relative to the game default.
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
Default value is 1. */
double m_NormalMaxSpeed;
-
+
/** Max speed, relative to the game default max speed, when sprinting.
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
Default value is 1.3. */
double m_SprintingMaxSpeed;
-
+
/** Max speed, relative to the game default flying max speed, when flying.
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
Default value is 1. */
double m_FlyingMaxSpeed;
-
+
bool m_IsCrouched;
bool m_IsSprinting;
bool m_IsFlying;
@@ -618,7 +632,7 @@ protected:
Will not apply food penalties if found to be true; will set to false after processing
*/
bool m_bIsTeleporting;
-
+
/** The short UUID (no dashes) of the player, as read from the ClientHandle.
If no ClientHandle is given, the UUID is initialized to empty. */
AString m_UUID;
@@ -631,14 +645,14 @@ protected:
void ResolvePermissions(void);
void ResolveGroups(void);
- virtual void Destroyed(void);
+ virtual void Destroyed(void) override;
- /** Filters out damage for creative mode/friendly fire */
+ /** Filters out damage for creative mode / friendly fire */
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
/** Stops players from burning in creative mode */
virtual void TickBurning(cChunk & a_Chunk) override;
-
+
/** Called in each tick to handle food-related processing */
void HandleFood(void);
@@ -655,7 +669,3 @@ protected:
This can be used both for online and offline UUIDs. */
AString GetUUIDFileName(const AString & a_UUID);
} ; // tolua_export
-
-
-
-
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 4684e3e09..05b7669cd 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -227,6 +227,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a
),
m_IsInGround(false)
{
+ SetGravity(-12.0f);
+ SetAirDrag(0.01f);
}
@@ -242,6 +244,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
SetSpeed(a_Speed);
SetYawFromSpeed();
SetPitchFromSpeed();
+ SetGravity(-12.0f);
+ SetAirDrag(0.01f);
}
@@ -349,9 +353,11 @@ void cProjectileEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a
return;
}
- const Vector3d PerTickSpeed = GetSpeed() / 20;
+ auto DtSec = std::chrono::duration_cast<std::chrono::duration<double>>(a_Dt);
+
+ const Vector3d DeltaSpeed = GetSpeed() * DtSec.count();
const Vector3d Pos = GetPosition();
- const Vector3d NextPos = Pos + PerTickSpeed;
+ const Vector3d NextPos = Pos + DeltaSpeed;
// Test for entity collisions:
cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos);
@@ -388,8 +394,8 @@ void cProjectileEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a
// Add slowdown and gravity effect to the speed:
Vector3d NewSpeed(GetSpeed());
- NewSpeed.y += m_Gravity / 20;
- NewSpeed *= TracerCallback.GetSlowdownCoeff();
+ NewSpeed.y += m_Gravity * DtSec.count();
+ NewSpeed -= NewSpeed * (m_AirDrag * 20.0f) * DtSec.count();
SetSpeed(NewSpeed);
SetYawFromSpeed();
SetPitchFromSpeed();
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index de460a8ad..7ee87f93a 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -109,7 +109,7 @@ protected:
eKind m_ProjectileKind;
/** The structure for containing the entity ID and name who has created this projectile
- The ID and/or name may be nullptr (e.g. for dispensers/mobs). */
+ The ID and / or name may be nullptr (e.g. for dispensers / mobs). */
CreatorData m_CreatorData;
/** True if the projectile has hit the ground and is stuck there */
diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp
index a89d2f300..d849bd4c9 100644
--- a/src/Entities/TNTEntity.cpp
+++ b/src/Entities/TNTEntity.cpp
@@ -12,6 +12,8 @@ cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks) :
super(etTNT, a_X, a_Y, a_Z, 0.98, 0.98),
m_FuseTicks(a_FuseTicks)
{
+ SetGravity(-16.0f);
+ SetAirDrag(0.02f);
}
@@ -22,6 +24,8 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) :
super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
m_FuseTicks(a_FuseTicks)
{
+ SetGravity(-16.0f);
+ SetAirDrag(0.4f);
}
diff --git a/src/Entities/WitherSkullEntity.cpp b/src/Entities/WitherSkullEntity.cpp
index a7e774bba..dc95e3edd 100644
--- a/src/Entities/WitherSkullEntity.cpp
+++ b/src/Entities/WitherSkullEntity.cpp
@@ -16,6 +16,8 @@ cWitherSkullEntity::cWitherSkullEntity(cEntity * a_Creator, double a_X, double a
super(pkWitherSkull, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
{
SetSpeed(a_Speed);
+ SetGravity(0);
+ SetAirDrag(0);
}