1
0
Fork 0

Basic elytra flight (#5124)

* Basic elytra flight

Co-authored-by: 12xx12 <44411062+12xx12@users.noreply.github.com>
Co-authored-by: Tiger Wang <ziwei.tiger@outlook.com>
This commit is contained in:
Damián Imrich 2021-04-03 19:45:20 +02:00 committed by GitHub
parent ce6f8b3557
commit 071b7be3d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 490 additions and 287 deletions

View File

@ -4071,6 +4071,16 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
}, },
Notes = "Returns true if the entity is sprinting. Entities that cannot sprint return always false", Notes = "Returns true if the entity is sprinting. Entities that cannot sprint return always false",
}, },
IsElytraFlying =
{
Returns =
{
{
Type = "boolean",
},
},
Notes = "Returns true if the entity is flying with an elytra. Entities that cannot fly with an elytra return always false",
},
IsSubmerged = IsSubmerged =
{ {
Returns = Returns =
@ -10537,16 +10547,6 @@ a_Player:OpenWindow(Window);
}, },
Notes = "Returns the player's current set of skin part flags. This is a bitwise OR of various {{Globals#eSkinPart|eSkinPart}} constants. Note that HasSkinPart may be easier to use in most situations.", Notes = "Returns the player's current set of skin part flags. This is a bitwise OR of various {{Globals#eSkinPart|eSkinPart}} constants. Note that HasSkinPart may be easier to use in most situations.",
}, },
GetStance =
{
Returns =
{
{
Type = "number",
},
},
Notes = "Returns the player's stance (Y-pos of player's eyes)",
},
GetTeam = GetTeam =
{ {
Returns = Returns =
@ -11277,6 +11277,17 @@ a_Player:OpenWindow(Window);
}, },
Notes = "Sets the skin part flags of the player. The value should be a bitwise OR of several {{Globals#eSkinPart|eSkinPart}} constants.", Notes = "Sets the skin part flags of the player. The value should be a bitwise OR of several {{Globals#eSkinPart|eSkinPart}} constants.",
}, },
SetElytraFlight =
{
Params =
{
{
Name = "IsElytraFlying",
Type = "boolean",
},
},
Notes = "Sets whether the player is elytra flying or not.",
},
SetSprintingMaxSpeed = SetSprintingMaxSpeed =
{ {
Params = Params =

View File

@ -574,12 +574,9 @@ void cClientHandle::HandleNPCTrade(int a_SlotNum)
void cClientHandle::HandleOpenHorseInventory(UInt32 a_EntityID) void cClientHandle::HandleOpenHorseInventory()
{ {
if (m_Player->GetUniqueID() == a_EntityID) m_Player->OpenHorseInventory();
{
m_Player->OpenHorseInventory();
}
} }
@ -665,6 +662,15 @@ void cClientHandle::HandleCreativeInventory(Int16 a_SlotNum, const cItem & a_Hel
void cClientHandle::HandleCrouch(const bool a_IsCrouching)
{
m_Player->SetCrouch(a_IsCrouching);
}
void cClientHandle::HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment) void cClientHandle::HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment)
{ {
if (a_Enchantment > 2) if (a_Enchantment > 2)
@ -749,7 +755,7 @@ void cClientHandle::HandlePlayerAbilities(bool a_IsFlying, float FlyingSpeed, fl
void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround) void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, bool a_IsOnGround)
{ {
if (m_Player->IsFrozen()) if (m_Player->IsFrozen())
{ {
@ -759,7 +765,6 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
Vector3d NewPosition(a_PosX, a_PosY, a_PosZ); Vector3d NewPosition(a_PosX, a_PosY, a_PosZ);
Vector3d OldPosition = GetPlayer()->GetPosition(); Vector3d OldPosition = GetPlayer()->GetPosition();
double OldStance = GetPlayer()->GetStance();
auto PreviousIsOnGround = GetPlayer()->IsOnGround(); auto PreviousIsOnGround = GetPlayer()->IsOnGround();
#ifdef __clang__ #ifdef __clang__
@ -769,7 +774,6 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
if ( if (
(OldPosition == NewPosition) && (OldPosition == NewPosition) &&
(OldStance == a_Stance) &&
(PreviousIsOnGround == a_IsOnGround) (PreviousIsOnGround == a_IsOnGround)
) )
{ {
@ -799,7 +803,6 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
// TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too // TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
m_Player->SetPosition(NewPosition); m_Player->SetPosition(NewPosition);
m_Player->SetStance(a_Stance);
m_Player->SetTouchGround(a_IsOnGround); m_Player->SetTouchGround(a_IsOnGround);
m_Player->UpdateMovementStats(NewPosition - OldPosition, PreviousIsOnGround); m_Player->UpdateMovementStats(NewPosition - OldPosition, PreviousIsOnGround);
} }
@ -1513,9 +1516,9 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO
void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround) void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_PosZ, float a_Rotation, float a_Pitch, bool a_IsOnGround)
{ {
HandlePlayerPos(a_PosX, a_PosY, a_PosZ, a_Stance, a_IsOnGround); HandlePlayerPos(a_PosX, a_PosY, a_PosZ, a_IsOnGround);
HandlePlayerLook(a_Rotation, a_Pitch, a_IsOnGround); HandlePlayerLook(a_Rotation, a_Pitch, a_IsOnGround);
} }
@ -1567,6 +1570,24 @@ void cClientHandle::HandleSpectate(const cUUID & a_PlayerUUID)
void cClientHandle::HandleSprint(const bool a_IsSprinting)
{
m_Player->SetSprint(a_IsSprinting);
}
void cClientHandle::HandleStartElytraFlight()
{
m_Player->SetElytraFlight(true);
}
void cClientHandle::HandleSteerVehicle(float a_Forward, float a_Sideways) void cClientHandle::HandleSteerVehicle(float a_Forward, float a_Sideways)
{ {
m_Player->SteerVehicle(a_Forward, a_Sideways); m_Player->SteerVehicle(a_Forward, a_Sideways);
@ -1831,47 +1852,11 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
void cClientHandle::HandleEntityCrouch(UInt32 a_EntityID, bool a_IsCrouching) void cClientHandle::HandleLeaveBed()
{ {
if (a_EntityID != m_Player->GetUniqueID()) cChunkInterface Interface(m_Player->GetWorld()->GetChunkMap());
{ cBlockBedHandler::SetBedOccupationState(Interface, m_Player->GetLastBedPos(), false);
// We should only receive entity actions from the entity that is performing the action m_Player->SetIsInBed(false);
return;
}
m_Player->SetCrouch(a_IsCrouching);
}
void cClientHandle::HandleEntityLeaveBed(UInt32 a_EntityID)
{
if (a_EntityID != m_Player->GetUniqueID())
{
// We should only receive entity actions from the entity that is performing the action
return;
}
cChunkInterface Interface(GetPlayer()->GetWorld()->GetChunkMap());
cBlockBedHandler::SetBedOccupationState(Interface, GetPlayer()->GetLastBedPos(), false);
GetPlayer()->SetIsInBed(false);
}
void cClientHandle::HandleEntitySprinting(UInt32 a_EntityID, bool a_IsSprinting)
{
if (a_EntityID != m_Player->GetUniqueID())
{
// We should only receive entity actions from the entity that is performing the action
return;
}
m_Player->SetSprint(a_IsSprinting);
} }

View File

@ -322,13 +322,12 @@ public: // tolua_export
a_ClickAction specifies whether the click was inside the window or not (caLeftClick or caLeftClickOutside). */ a_ClickAction specifies whether the click was inside the window or not (caLeftClick or caLeftClickOutside). */
void HandleCreativeInventory(Int16 a_SlotNum, const cItem & a_HeldItem, eClickAction a_ClickAction); void HandleCreativeInventory(Int16 a_SlotNum, const cItem & a_HeldItem, eClickAction a_ClickAction);
/** Handles a player sneaking or unsneaking. */
void HandleCrouch(bool a_IsCrouching);
/** Called when the player enchants an Item in the Enchanting table UI. */ /** Called when the player enchants an Item in the Enchanting table UI. */
void HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment); void HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment);
void HandleEntityCrouch (UInt32 a_EntityID, bool a_IsCrouching);
void HandleEntityLeaveBed (UInt32 a_EntityID);
void HandleEntitySprinting (UInt32 a_EntityID, bool a_IsSprinting);
/** Kicks the client if the same username is already logged in. /** Kicks the client if the same username is already logged in.
Returns false if the client has been kicked, true otherwise. */ Returns false if the client has been kicked, true otherwise. */
bool CheckMultiLogin(const AString & a_Username); bool CheckMultiLogin(const AString & a_Username);
@ -339,6 +338,9 @@ public: // tolua_export
*/ */
bool HandleHandshake (const AString & a_Username); bool HandleHandshake (const AString & a_Username);
/** Handles a player exiting his bed. */
void HandleLeaveBed();
void HandleKeepAlive (UInt32 a_KeepAliveID); void HandleKeepAlive (UInt32 a_KeepAliveID);
void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, UInt8 a_Status); void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, UInt8 a_Status);
@ -346,20 +348,19 @@ public: // tolua_export
the NPC UI. */ the NPC UI. */
void HandleNPCTrade(int a_SlotNum); void HandleNPCTrade(int a_SlotNum);
/** Handles a player opening their inventory while riding a horse. /** Handles a player opening his inventory while riding a horse. */
@param a_EntityID ID of the player that is to open the inventory. Should be the same as GetPlayer()->GetUniqueID(). */ void HandleOpenHorseInventory();
void HandleOpenHorseInventory(UInt32 a_EntityID);
void HandlePing (void); void HandlePing (void);
void HandlePlayerAbilities (bool a_IsFlying, float FlyingSpeed, float WalkingSpeed); void HandlePlayerAbilities (bool a_IsFlying, float FlyingSpeed, float WalkingSpeed);
void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround); void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround);
void HandlePlayerMoveLook (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround); // While m_bPositionConfirmed (normal gameplay) void HandlePlayerMoveLook (double a_PosX, double a_PosY, double a_PosZ, float a_Rotation, float a_Pitch, bool a_IsOnGround); // While m_bPositionConfirmed (normal gameplay)
/** Verifies and sets player position, performing relevant checks /** Verifies and sets player position, performing relevant checks
Calls relevant methods to process movement related statistics Calls relevant methods to process movement related statistics
Requires state of previous position and on-ground status, so must be called when these are still intact Requires state of previous position and on-ground status, so must be called when these are still intact
*/ */
void HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround); void HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, bool a_IsOnGround);
void HandlePluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message); void HandlePluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message);
@ -367,6 +368,13 @@ public: // tolua_export
void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, eHand a_Hand); void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, eHand a_Hand);
void HandleSlotSelected (Int16 a_SlotNum); void HandleSlotSelected (Int16 a_SlotNum);
void HandleSpectate (const cUUID & a_PlayerUUID); void HandleSpectate (const cUUID & a_PlayerUUID);
/** Handles a player sprinting or slowing back down. */
void HandleSprint(bool a_IsSprinting);
/** Handles a player starting elytra flight while falling. */
void HandleStartElytraFlight();
void HandleSteerVehicle (float Forward, float Sideways); void HandleSteerVehicle (float Forward, float Sideways);
void HandleTabCompletion (const AString & a_Text); void HandleTabCompletion (const AString & a_Text);
void HandleUpdateSign ( void HandleUpdateSign (

View File

@ -535,6 +535,7 @@ bool ItemCategory::IsHelmet(short a_ItemType)
bool ItemCategory::IsChestPlate(short a_ItemType) bool ItemCategory::IsChestPlate(short a_ItemType)
{ {
return ( return (
(a_ItemType == E_ITEM_ELYTRA) ||
(a_ItemType == E_ITEM_LEATHER_TUNIC) || (a_ItemType == E_ITEM_LEATHER_TUNIC) ||
(a_ItemType == E_ITEM_GOLD_CHESTPLATE) || (a_ItemType == E_ITEM_GOLD_CHESTPLATE) ||
(a_ItemType == E_ITEM_CHAIN_CHESTPLATE) || (a_ItemType == E_ITEM_CHAIN_CHESTPLATE) ||

View File

@ -59,6 +59,8 @@ cEntity::cEntity(eEntityType a_EntityType, Vector3d a_Pos, double a_Width, doubl
m_IsInLava(false), m_IsInLava(false),
m_IsInWater(false), m_IsInWater(false),
m_IsHeadInWater(false), m_IsHeadInWater(false),
m_Width(a_Width),
m_Height(a_Height),
m_AirLevel(MAX_AIR_LEVEL), m_AirLevel(MAX_AIR_LEVEL),
m_AirTickTimer(DROWNING_TICKS), m_AirTickTimer(DROWNING_TICKS),
m_TicksAlive(0), m_TicksAlive(0),
@ -69,8 +71,6 @@ cEntity::cEntity(eEntityType a_EntityType, Vector3d a_Pos, double a_Width, doubl
m_Position(a_Pos), m_Position(a_Pos),
m_WaterSpeed(0, 0, 0), m_WaterSpeed(0, 0, 0),
m_Mass (0.001), // Default 1g m_Mass (0.001), // Default 1g
m_Width(a_Width),
m_Height(a_Height),
m_InvulnerableTicks(0) m_InvulnerableTicks(0)
{ {
m_WorldChangeInfo.m_NewWorld = nullptr; m_WorldChangeInfo.m_NewWorld = nullptr;
@ -2028,15 +2028,6 @@ void cEntity::SetHeadYaw(double a_HeadYaw)
void cEntity::SetHeight(double a_Height)
{
m_Height = a_Height;
}
void cEntity::SetMass(double a_Mass) void cEntity::SetMass(double a_Mass)
{ {
// Make sure that mass is not zero. 1g is the default because we // Make sure that mass is not zero. 1g is the default because we
@ -2118,15 +2109,6 @@ void cEntity::SetSpeedZ(double a_SpeedZ)
void cEntity::SetWidth(double a_Width)
{
m_Width = a_Width;
}
void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeedZ) void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeedZ)
{ {
SetSpeed(m_Speed.x + a_AddSpeedX, m_Speed.y + a_AddSpeedY, m_Speed.z + a_AddSpeedZ); SetSpeed(m_Speed.x + a_AddSpeedX, m_Speed.y + a_AddSpeedY, m_Speed.z + a_AddSpeedZ);

View File

@ -328,10 +328,6 @@ public:
// tolua_end // tolua_end
void SetHeight(double a_Height);
void SetWidth(double a_Width);
/** Exported in ManualBindings */ /** Exported in ManualBindings */
const Vector3d & GetPosition(void) const { return m_Position; } const Vector3d & GetPosition(void) const { return m_Position; }
@ -522,12 +518,13 @@ public:
// tolua_begin // tolua_begin
// COMMON metadata flags; descendants may override the defaults: // COMMON metadata flags; descendants may override the defaults:
virtual bool IsOnFire (void) const {return (m_TicksLeftBurning > 0); } virtual bool IsCrouched (void) const { return false; }
virtual bool IsCrouched (void) const {return false; } virtual bool IsElytraFlying(void) const { return false; }
virtual bool IsRiding (void) const {return false; } virtual bool IsInvisible (void) const { return false; }
virtual bool IsSprinting(void) const {return false; } virtual bool IsOnFire (void) const { return m_TicksLeftBurning > 0; }
virtual bool IsRclking (void) const {return false; } virtual bool IsRclking (void) const { return false; }
virtual bool IsInvisible(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 */ /** Returns true if any part of the entity is in a fire block */
virtual bool IsInFire(void) const { return m_IsInFire; } virtual bool IsInFire(void) const { return m_IsInFire; }
@ -689,6 +686,12 @@ protected:
/** If the entity's head is in a water block */ /** If the entity's head is in a water block */
bool m_IsHeadInWater; bool m_IsHeadInWater;
/** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */
double m_Width;
/** Height of the entity (Y axis). */
double m_Height;
/** Air level of a mobile */ /** Air level of a mobile */
int m_AirLevel; int m_AirLevel;
int m_AirTickTimer; int m_AirTickTimer;
@ -745,12 +748,6 @@ private:
/** Measured in Kilograms (Kg) */ /** Measured in Kilograms (Kg) */
double m_Mass; double m_Mass;
/** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */
double m_Width;
/** Height of the entity (Y axis) */
double m_Height;
/** If a player hit a entity, the entity receive a invulnerable of 10 ticks. /** If a player hit a entity, the entity receive a invulnerable of 10 ticks.
While this ticks, a player can't hit this entity. */ While this ticks, a player can't hit this entity. */
int m_InvulnerableTicks; int m_InvulnerableTicks;

View File

@ -106,8 +106,6 @@ cMinecart::cMinecart(ePayload a_Payload, Vector3d a_Pos):
SetAirDrag(0.05f); SetAirDrag(0.05f);
SetMaxHealth(6); SetMaxHealth(6);
SetHealth(6); SetHealth(6);
SetWidth(1);
SetHeight(0.9);
} }
@ -1274,10 +1272,10 @@ void cMinecart::ApplyAcceleration(Vector3d a_ForwardDirection, double a_Accelera
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cRideableMinecart: // cRideableMinecart:
cRideableMinecart::cRideableMinecart(Vector3d a_Pos, const cItem & a_Content, int a_Height): cRideableMinecart::cRideableMinecart(Vector3d a_Pos, const cItem & a_Content, int a_ContentHeight):
Super(mpNone, a_Pos), Super(mpNone, a_Pos),
m_Content(a_Content), m_Content(a_Content),
m_Height(a_Height) m_ContentHeight(a_ContentHeight)
{ {
} }

View File

@ -105,10 +105,10 @@ public:
CLASS_PROTODEF(cRideableMinecart) CLASS_PROTODEF(cRideableMinecart)
cRideableMinecart(Vector3d a_Pos, const cItem & a_Content, int a_Height); cRideableMinecart(Vector3d a_Pos, const cItem & a_Content, int a_ContentHeight);
const cItem & GetContent(void) const {return m_Content;} const cItem & GetContent(void) const { return m_Content; }
int GetBlockHeight(void) const {return m_Height;} int GetBlockHeight(void) const { return m_ContentHeight; }
// cEntity overrides: // cEntity overrides:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
@ -116,9 +116,8 @@ public:
protected: protected:
cItem m_Content; cItem m_Content;
int m_Height; int m_ContentHeight;
} ; } ;

View File

@ -418,6 +418,11 @@ void cPawn::HandleFalling(void)
auto Damage = static_cast<int>(m_LastGroundHeight - GetPosY() - 3.0); auto Damage = static_cast<int>(m_LastGroundHeight - GetPosY() - 3.0);
if ((Damage > 0) && !FallDamageAbsorbed) if ((Damage > 0) && !FallDamageAbsorbed)
{ {
if (IsElytraFlying())
{
Damage = static_cast<int>(static_cast<float>(Damage) * 0.33);
}
TakeDamage(dtFalling, nullptr, Damage, static_cast<float>(Damage), 0); TakeDamage(dtFalling, nullptr, Damage, static_cast<float>(Damage), 0);
// Fall particles // Fall particles

View File

@ -66,38 +66,72 @@ const int cPlayer::EATING_TICKS = 30;
cPlayer::BodyStanceCrouching::BodyStanceCrouching(cPlayer & a_Player)
{
a_Player.SetSize(0.6f, 1.65f);
}
cPlayer::BodyStanceSleeping::BodyStanceSleeping(cPlayer & a_Player)
{
a_Player.SetSize(0.2f, 0.2f);
}
cPlayer::BodyStanceStanding::BodyStanceStanding(cPlayer & a_Player)
{
a_Player.SetSize(0.6f, 1.8f);
}
cPlayer::BodyStanceGliding::BodyStanceGliding(cPlayer & a_Player) :
TicksElytraFlying(0)
{
a_Player.SetSize(0.6f, 0.6f);
}
cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) : cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) :
Super(etPlayer, 0.6, 1.8), Super(etPlayer, 0.6, 1.8),
m_bVisible(true), m_BodyStance(BodyStanceStanding(*this)),
m_FoodLevel(MAX_FOOD_LEVEL), m_FoodLevel(MAX_FOOD_LEVEL),
m_FoodSaturationLevel(5.0), m_FoodSaturationLevel(5.0),
m_FoodTickTimer(0), m_FoodTickTimer(0),
m_FoodExhaustionLevel(0.0), m_FoodExhaustionLevel(0.0),
m_Stance(0.0),
m_Inventory(*this), m_Inventory(*this),
m_EnderChestContents(9, 3), m_EnderChestContents(9, 3),
m_DefaultWorldPath(cRoot::Get()->GetDefaultWorld()->GetDataPath()), m_DefaultWorldPath(cRoot::Get()->GetDefaultWorld()->GetDataPath()),
m_GameMode(eGameMode_NotSet), m_GameMode(eGameMode_NotSet),
m_ClientHandle(a_Client), m_ClientHandle(a_Client),
m_IsFrozen(false),
m_NormalMaxSpeed(1.0), m_NormalMaxSpeed(1.0),
m_SprintingMaxSpeed(1.3), m_SprintingMaxSpeed(1.3),
m_FlyingMaxSpeed(1.0), m_FlyingMaxSpeed(1.0),
m_IsCrouched(false), m_IsChargingBow(false),
m_IsSprinting(false),
m_IsFlying(false),
m_IsFishing(false), m_IsFishing(false),
m_CanFly(false), m_IsFlightCapable(false),
m_IsFlying(false),
m_IsFrozen(false),
m_IsTeleporting(false),
m_IsVisible(true),
m_EatingFinishTick(-1), m_EatingFinishTick(-1),
m_LifetimeTotalXp(0), m_LifetimeTotalXp(0),
m_CurrentXp(0), m_CurrentXp(0),
m_IsChargingBow(false),
m_BowCharge(0), m_BowCharge(0),
m_FloaterID(cEntity::INVALID_ID), m_FloaterID(cEntity::INVALID_ID),
m_Team(nullptr), m_Team(nullptr),
m_bIsInBed(false),
m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL),
m_bIsTeleporting(false),
m_SkinParts(0), m_SkinParts(0),
m_MainHand(mhRight) m_MainHand(mhRight)
{ {
@ -114,26 +148,25 @@ cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) :
LoadFromDisk(World); LoadFromDisk(World);
m_LastGroundHeight = static_cast<float>(GetPosY()); m_LastGroundHeight = static_cast<float>(GetPosY());
m_Stance = GetPosY() + 1.62;
if (m_GameMode == gmNotSet) if (m_GameMode == gmNotSet)
{ {
if (World->IsGameModeCreative()) if (World->IsGameModeCreative())
{ {
m_CanFly = true; m_IsFlightCapable = true;
} }
if (World->IsGameModeSpectator()) // Otherwise Player will fall out of the world on join if (World->IsGameModeSpectator()) // Otherwise Player will fall out of the world on join
{ {
m_CanFly = true; m_IsFlightCapable = true;
m_IsFlying = true; m_IsFlying = true;
} }
} }
if (m_GameMode == gmSpectator) // If player is reconnecting to the server in spectator mode if (m_GameMode == gmSpectator) // If player is reconnecting to the server in spectator mode
{ {
m_CanFly = true; m_IsFlightCapable = true;
m_IsFlying = true; m_IsFlying = true;
m_bVisible = false; m_IsVisible = false;
} }
} }
@ -427,6 +460,24 @@ void cPlayer::AddFoodExhaustion(double a_Exhaustion)
bool cPlayer::IsInBed(void) const
{
return std::holds_alternative<BodyStanceSleeping>(m_BodyStance);
}
bool cPlayer::IsStanding() const
{
return std::holds_alternative<BodyStanceStanding>(m_BodyStance);
}
void cPlayer::TossItems(const cItems & a_Items) void cPlayer::TossItems(const cItems & a_Items)
{ {
if (IsGameModeSpectator()) // Players can't toss items in spectator if (IsGameModeSpectator()) // Players can't toss items in spectator
@ -445,6 +496,23 @@ void cPlayer::TossItems(const cItems & a_Items)
void cPlayer::SetIsInBed(const bool a_GoToBed)
{
if (a_GoToBed && IsStanding())
{
m_BodyStance = BodyStanceSleeping(*this);
}
else if (!a_GoToBed && IsInBed())
{
m_BodyStance = BodyStanceStanding(*this);
GetWorld()->BroadcastEntityAnimation(*this, 2);
}
}
void cPlayer::StartEating(void) void cPlayer::StartEating(void)
{ {
// Set the timer: // Set the timer:
@ -525,11 +593,11 @@ const cSlotNums & cPlayer::GetInventoryPaintSlots(void) const
double cPlayer::GetMaxSpeed(void) const double cPlayer::GetMaxSpeed(void) const
{ {
if (m_IsFlying) if (IsFlying())
{ {
return m_FlyingMaxSpeed; return m_FlyingMaxSpeed;
} }
else if (m_IsSprinting) else if (IsSprinting())
{ {
return m_SprintingMaxSpeed; return m_SprintingMaxSpeed;
} }
@ -546,7 +614,7 @@ double cPlayer::GetMaxSpeed(void) const
void cPlayer::SetNormalMaxSpeed(double a_Speed) void cPlayer::SetNormalMaxSpeed(double a_Speed)
{ {
m_NormalMaxSpeed = a_Speed; m_NormalMaxSpeed = a_Speed;
if (!m_IsSprinting && !m_IsFlying && !m_IsFrozen) if (!IsSprinting() && !IsFlying() && !IsFrozen())
{ {
// If we are frozen, we do not send this yet. We send when unfreeze() is called // If we are frozen, we do not send this yet. We send when unfreeze() is called
m_ClientHandle->SendPlayerMaxSpeed(); m_ClientHandle->SendPlayerMaxSpeed();
@ -560,7 +628,7 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
void cPlayer::SetSprintingMaxSpeed(double a_Speed) void cPlayer::SetSprintingMaxSpeed(double a_Speed)
{ {
m_SprintingMaxSpeed = a_Speed; m_SprintingMaxSpeed = a_Speed;
if (m_IsSprinting && !m_IsFlying && !m_IsFrozen) if (IsSprinting() && !m_IsFlying && !m_IsFrozen)
{ {
// If we are frozen, we do not send this yet. We send when unfreeze() is called // If we are frozen, we do not send this yet. We send when unfreeze() is called
m_ClientHandle->SendPlayerMaxSpeed(); m_ClientHandle->SendPlayerMaxSpeed();
@ -587,21 +655,18 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed)
void cPlayer::SetCrouch(bool a_IsCrouched) void cPlayer::SetCrouch(const bool a_ShouldCrouch)
{ {
// Set the crouch status, broadcast to all visible players if (a_ShouldCrouch && IsStanding())
if (a_IsCrouched == m_IsCrouched)
{
// No change
return;
}
if (a_IsCrouched)
{ {
m_BodyStance = BodyStanceCrouching(*this);
cRoot::Get()->GetPluginManager()->CallHookPlayerCrouched(*this); cRoot::Get()->GetPluginManager()->CallHookPlayerCrouched(*this);
} }
else if (!a_ShouldCrouch && IsCrouched())
{
m_BodyStance = BodyStanceStanding(*this);
}
m_IsCrouched = a_IsCrouched;
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
} }
@ -609,16 +674,55 @@ void cPlayer::SetCrouch(bool a_IsCrouched)
void cPlayer::SetSprint(bool a_IsSprinting) void cPlayer::SetElytraFlight(const bool a_ShouldElytraFly)
{ {
if (a_IsSprinting == m_IsSprinting) if (a_ShouldElytraFly && IsStanding() && !IsOnGround() && !IsInWater() && !IsRiding() && (GetEquippedChestplate().m_ItemType == E_ITEM_ELYTRA))
{
m_BodyStance = BodyStanceGliding(*this);
}
else if (!a_ShouldElytraFly && IsElytraFlying())
{
m_BodyStance = BodyStanceStanding(*this);
}
m_World->BroadcastEntityMetadata(*this);
}
void cPlayer::SetFlying(const bool a_ShouldFly)
{
if (a_ShouldFly == m_IsFlying)
{ {
// No change
return; return;
} }
m_IsSprinting = a_IsSprinting; m_IsFlying = a_ShouldFly;
m_ClientHandle->SendPlayerMaxSpeed(); if (!m_IsFrozen)
{
// If we are frozen, we do not send this yet. We send when unfreeze() is called
m_ClientHandle->SendPlayerAbilities();
}
}
void cPlayer::SetSprint(const bool a_ShouldSprint)
{
if (a_ShouldSprint && IsStanding())
{
m_BodyStance = BodyStanceSprinting();
}
else if (!a_ShouldSprint && IsSprinting())
{
m_BodyStance = BodyStanceStanding(*this);
}
m_World->BroadcastEntityMetadata(*this);
} }
@ -627,12 +731,12 @@ void cPlayer::SetSprint(bool a_IsSprinting)
void cPlayer::SetCanFly(bool a_CanFly) void cPlayer::SetCanFly(bool a_CanFly)
{ {
if (a_CanFly == m_CanFly) if (a_CanFly == m_IsFlightCapable)
{ {
return; return;
} }
m_CanFly = a_CanFly; m_IsFlightCapable = a_CanFly;
m_ClientHandle->SendPlayerAbilities(); m_ClientHandle->SendPlayerAbilities();
} }
@ -698,25 +802,6 @@ cWorld * cPlayer::GetBedWorld()
void cPlayer::SetFlying(bool a_IsFlying)
{
if (a_IsFlying == m_IsFlying)
{
return;
}
m_IsFlying = a_IsFlying;
if (!m_IsFrozen)
{
// If we are frozen, we do not send this yet. We send when unfreeze() is called
m_ClientHandle->SendPlayerAbilities();
}
}
void cPlayer::NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved) void cPlayer::NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved)
{ {
ASSERT(a_Opponent != nullptr); ASSERT(a_Opponent != nullptr);
@ -750,7 +835,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI)
return; // not dead yet =] return; // not dead yet =]
} }
m_bVisible = false; // So new clients don't see the player m_IsVisible = false; // So new clients don't see the player
// Detach player from object / entity. If the player dies, the server still says // Detach player from object / entity. If the player dies, the server still says
// that the player is attached to the entity / object // that the player is attached to the entity / object
@ -905,7 +990,7 @@ void cPlayer::Respawn(void)
double cPlayer::GetEyeHeight(void) const double cPlayer::GetEyeHeight(void) const
{ {
return m_Stance; return GetEyePosition().y - GetPosY();
} }
@ -914,7 +999,22 @@ double cPlayer::GetEyeHeight(void) const
Vector3d cPlayer::GetEyePosition(void) const Vector3d cPlayer::GetEyePosition(void) const
{ {
return Vector3d( GetPosX(), m_Stance, GetPosZ()); if (IsCrouched())
{
return GetPosition().addedY(1.54);
}
if (IsElytraFlying())
{
return GetPosition().addedY(0.4);
}
if (IsInBed())
{
return GetPosition().addedY(0.2);
}
return GetPosition().addedY(1.6);
} }
@ -1314,7 +1414,7 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
{ {
SetPosition({a_PosX, a_PosY, a_PosZ}); SetPosition({a_PosX, a_PosY, a_PosZ});
FreezeInternal(GetPosition(), false); FreezeInternal(GetPosition(), false);
m_bIsTeleporting = true; m_IsTeleporting = true;
m_ClientHandle->SendPlayerMoveLook(); m_ClientHandle->SendPlayerMoveLook();
} }
@ -1344,6 +1444,11 @@ bool cPlayer::IsFrozen()
void cPlayer::Unfreeze() void cPlayer::Unfreeze()
{ {
if (IsElytraFlying())
{
m_World->BroadcastEntityMetadata(*this);
}
GetClientHandle()->SendPlayerAbilities(); GetClientHandle()->SendPlayerAbilities();
GetClientHandle()->SendPlayerMaxSpeed(); GetClientHandle()->SendPlayerMaxSpeed();
@ -1449,14 +1554,14 @@ void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
void cPlayer::SetVisible(bool a_bVisible) void cPlayer::SetVisible(bool a_bVisible)
{ {
// Need to Check if the player or other players are in gamemode spectator, but will break compatibility // Need to Check if the player or other players are in gamemode spectator, but will break compatibility
if (a_bVisible && !m_bVisible) // Make visible if (a_bVisible && !m_IsVisible) // Make visible
{ {
m_bVisible = true; m_IsVisible = true;
m_World->BroadcastSpawnEntity(*this); m_World->BroadcastSpawnEntity(*this);
} }
if (!a_bVisible && m_bVisible) if (!a_bVisible && m_IsVisible)
{ {
m_bVisible = false; m_IsVisible = false;
m_World->BroadcastDestroyEntity(*this, m_ClientHandle.get()); // Destroy on all clients m_World->BroadcastDestroyEntity(*this, m_ClientHandle.get()); // Destroy on all clients
} }
} }
@ -1809,7 +1914,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
if (m_GameMode == eGameMode_Creative) if (m_GameMode == eGameMode_Creative)
{ {
m_CanFly = true; m_IsFlightCapable = true;
} }
m_Inventory.LoadFromJson(Root["inventory"]); m_Inventory.LoadFromJson(Root["inventory"]);
@ -2141,9 +2246,9 @@ bool cPlayer::IsClimbing(void) const
void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround) void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround)
{ {
if (m_bIsTeleporting) if (m_IsTeleporting)
{ {
m_bIsTeleporting = false; m_IsTeleporting = false;
return; return;
} }
@ -2599,16 +2704,19 @@ float cPlayer::GetLiquidHeightPercent(NIBBLETYPE a_Meta)
bool cPlayer::IsInsideWater() bool cPlayer::IsInsideWater()
{ {
BLOCKTYPE Block = m_World->GetBlock(Vector3d(GetPosX(), m_Stance, GetPosZ()).Floor()); BLOCKTYPE Block;
NIBBLETYPE Meta;
m_World->GetBlockTypeMeta(GetEyePosition().Floor(), Block, Meta);
if ((Block != E_BLOCK_WATER) && (Block != E_BLOCK_STATIONARY_WATER)) if ((Block != E_BLOCK_WATER) && (Block != E_BLOCK_STATIONARY_WATER))
{ {
return false; return false;
} }
NIBBLETYPE Meta = GetWorld()->GetBlockMeta(Vector3d(GetPosX(), m_Stance, GetPosZ()).Floor());
const auto EyeHeight = GetEyeHeight();
float f = GetLiquidHeightPercent(Meta) - 0.11111111f; float f = GetLiquidHeightPercent(Meta) - 0.11111111f;
float f1 = static_cast<float>(m_Stance + 1) - f; float f1 = static_cast<float>(EyeHeight + 1) - f;
bool flag = (m_Stance < f1); return EyeHeight < f1;
return flag;
} }
@ -2742,6 +2850,16 @@ void cPlayer::AddKnownItem(const cItem & a_Item)
void cPlayer::SetSize(const float a_Width, const float a_Height)
{
m_Width = a_Width;
m_Height = a_Height;
}
void cPlayer::AddKnownRecipe(UInt32 a_RecipeId) void cPlayer::AddKnownRecipe(UInt32 a_RecipeId)
{ {
auto Response = m_KnownRecipes.insert(a_RecipeId); auto Response = m_KnownRecipes.insert(a_RecipeId);
@ -2916,6 +3034,33 @@ float cPlayer::GetEnchantmentBlastKnockbackReduction()
bool cPlayer::IsCrouched(void) const
{
return std::holds_alternative<BodyStanceCrouching>(m_BodyStance);
}
bool cPlayer::IsElytraFlying(void) const
{
return std::holds_alternative<BodyStanceGliding>(m_BodyStance);
}
bool cPlayer::IsSprinting(void) const
{
return std::holds_alternative<BodyStanceSprinting>(m_BodyStance);
}
void cPlayer::OnAddToWorld(cWorld & a_World) void cPlayer::OnAddToWorld(cWorld & a_World)
{ {
Super::OnAddToWorld(a_World); Super::OnAddToWorld(a_World);
@ -3023,7 +3168,7 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
void cPlayer::SpawnOn(cClientHandle & a_Client) void cPlayer::SpawnOn(cClientHandle & a_Client)
{ {
if (!m_bVisible || (m_ClientHandle.get() == (&a_Client))) if (!m_IsVisible || (m_ClientHandle.get() == (&a_Client)))
{ {
return; return;
} }
@ -3110,6 +3255,27 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
m_BowCharge += 1; m_BowCharge += 1;
} }
if (IsElytraFlying())
{
// Damage elytra, once per second:
{
using namespace std::chrono_literals;
auto & TicksFlying = std::get<BodyStanceGliding>(m_BodyStance).TicksElytraFlying;
const auto TotalFlew = TicksFlying + a_Dt;
const auto Periods = static_cast<short>(TotalFlew / 1s);
TicksFlying = std::chrono::duration_cast<cTickTime>(TotalFlew - Periods * 1s);
UseItem(cInventory::invArmorOffset + 1, Periods);
}
// Check if flight is still possible:
if (IsOnGround() || IsInWater() || IsRiding() || (GetEquippedChestplate().m_ItemType != E_ITEM_ELYTRA))
{
SetElytraFlight(false);
}
}
BroadcastMovementUpdate(m_ClientHandle.get()); BroadcastMovementUpdate(m_ClientHandle.get());
if (m_Health > 0) // make sure player is alive if (m_Health > 0) // make sure player is alive

View File

@ -27,11 +27,57 @@ class cTeam;
class cPlayer: class cPlayer:
public cPawn public cPawn
{ {
// tolua_end // tolua_end
using Super = cPawn; using Super = cPawn;
/** Tag representing a sneaking pose. */
struct BodyStanceCrouching
{
BodyStanceCrouching(cPlayer & a_Player);
};
/** Tag representing a sleeping pose.
Set by a right click on unoccupied bed, unset by a time fast forward or teleport. */
struct BodyStanceSleeping
{
BodyStanceSleeping(cPlayer & a_Player);
};
/** Tag representing a sprinting pose. */
struct BodyStanceSprinting
{
};
/** Tag representing the neutral stance. */
struct BodyStanceStanding
{
BodyStanceStanding(cPlayer & a_Player);
};
/** Tag representing a swimming or elytra flying pose. */
struct BodyStanceGliding
{
BodyStanceGliding(cPlayer & a_Player);
cTickTime TicksElytraFlying;
};
/*
struct HandStanceNeutral
{
};
struct HandStandChargingBow
{
int m_BowCharge;
};
struct HandStanceEating
{
};
*/
// tolua_begin // tolua_begin
public: public:
@ -105,11 +151,8 @@ public:
bool IsChargingBow(void) const { return m_IsChargingBow; } bool IsChargingBow(void) const { return m_IsChargingBow; }
void SetTouchGround(bool a_bTouchGround); void SetTouchGround(bool a_bTouchGround);
inline void SetStance(const double a_Stance) { m_Stance = a_Stance; }
double GetEyeHeight(void) const; // tolua_export double GetEyeHeight(void) const; // tolua_export
Vector3d GetEyePosition(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 m_Stance; } // tolua_export
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
inline const cInventory & GetInventory(void) const { return m_Inventory; } inline const cInventory & GetInventory(void) const { return m_Inventory; }
@ -333,8 +376,8 @@ public:
/** Returns true if the player is currently flying */ /** Returns true if the player is currently flying */
bool IsFlying(void) const { return m_IsFlying; } bool IsFlying(void) const { return m_IsFlying; }
/** Returns true if a player is sleeping in a bed */ /** Returns true if a player is sleeping in a bed. */
bool IsInBed(void) const { return m_bIsInBed; } bool IsInBed(void) const;
/** Returns true if the player has thrown out a floater */ /** Returns true if the player has thrown out a floater */
bool IsFishing(void) const { return m_IsFishing; } bool IsFishing(void) const { return m_IsFishing; }
@ -345,21 +388,16 @@ public:
// tolua_end // tolua_end
/** Returns true if a player is standing normally, that is, in a neutral pose. */
bool IsStanding() const;
/** Tosses a list of items. */ /** Tosses a list of items. */
void TossItems(const cItems & a_Items); void TossItems(const cItems & a_Items);
/** Sets a player's in-bed state /** Sets a player's in-bed state.
We can't be sure plugins will keep this value updated, so no exporting We can't be sure plugins will keep this value updated, so no exporting.
If value is false (not in bed), will update players of the fact that they have been ejected from the bed If value is false (not in bed), will update players of the fact that they have been ejected from the bed. */
*/ void SetIsInBed(bool a_IsInBed);
void SetIsInBed(bool a_Flag)
{
m_bIsInBed = a_Flag;
if (!a_Flag)
{
GetWorld()->BroadcastEntityAnimation(*this, 2);
}
}
/** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */ /** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
void StartEating(void); void StartEating(void);
@ -377,7 +415,7 @@ public:
void Respawn(void); // tolua_export void Respawn(void); // tolua_export
void SetVisible( bool a_bVisible); // tolua_export void SetVisible( bool a_bVisible); // tolua_export
bool IsVisible(void) const { return m_bVisible; } // tolua_export bool IsVisible(void) const { return m_IsVisible; } // tolua_export
/** Saves all player data, such as inventory, to JSON. */ /** Saves all player data, such as inventory, to JSON. */
void SaveToDisk(void); void SaveToDisk(void);
@ -450,14 +488,17 @@ public:
/** Sets the flying relative maximum speed. Sends the update to player, if needed. */ /** Sets the flying relative maximum speed. Sends the update to player, if needed. */
void SetFlyingMaxSpeed(double a_Speed); void SetFlyingMaxSpeed(double a_Speed);
/** Sets the crouch status, broadcasts to all visible players */ /** Starts or stops crouching, if our current body stance permits, broadcasting the state change. */
void SetCrouch(bool a_IsCrouched); void SetCrouch(bool a_ShouldCrouch);
/** Starts or stops sprinting, sends the max speed update to the client, if needed */ /** Starts or stops elytra flight, if our current body stance permits, broadcasting the state change. */
void SetSprint(bool a_IsSprinting); void SetElytraFlight(bool a_ShouldElytraFly);
/** Flags the player as flying */ /** Starts or stops flying, broadcasting the state change. */
void SetFlying(bool a_IsFlying); void SetFlying(bool a_ShouldFly);
/** Starts or stops sprinting, if our current body stance permits, broadcasting the state change. */
void SetSprint(bool a_ShouldSprint);
/** If true the player can fly even when he's not in creative. */ /** If true the player can fly even when he's not in creative. */
void SetCanFly(bool a_CanFly); void SetCanFly(bool a_CanFly);
@ -501,7 +542,7 @@ public:
// tolua_begin // tolua_begin
/** Returns wheter the player can fly or not. */ /** Returns wheter the player can fly or not. */
virtual bool CanFly(void) const { return m_CanFly; } virtual bool CanFly(void) const { return m_IsFlightCapable; }
/** (Re)loads the rank and permissions from the cRankManager. /** (Re)loads the rank and permissions from the cRankManager.
Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */ Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */
@ -541,14 +582,6 @@ public:
*/ */
void NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved); void NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved);
// cEntity overrides:
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 AttachTo(cEntity * a_AttachTo) override;
virtual void Detach(void) override;
/** Returns the progress mined per tick for the block a_Block as a fraction /** Returns the progress mined per tick for the block a_Block as a fraction
(1 would be completely mined) (1 would be completely mined)
Depends on hardness values so check those are correct. Depends on hardness values so check those are correct.
@ -565,18 +598,38 @@ public:
If the item is already known, does nothing. */ If the item is already known, does nothing. */
void AddKnownItem(const cItem & a_Item); void AddKnownItem(const cItem & a_Item);
/** Update a player's size, for example, on body stance changes. */
void SetSize(float a_Width, float a_Height);
// cEntity overrides: // cEntity overrides:
virtual void AttachTo(cEntity * a_AttachTo) override;
virtual void Detach(void) override;
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); } virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); } virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); } virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); }
virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); } virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); }
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); } virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
virtual cItem GetOffHandEquipedItem(void) const override { return m_Inventory.GetShieldSlot(); } virtual cItem GetOffHandEquipedItem(void) const override { return m_Inventory.GetShieldSlot(); }
virtual bool IsCrouched(void) const override;
virtual bool IsElytraFlying(void) const override;
virtual bool IsOnGround(void) const override { return m_bTouchGround; }
virtual bool IsSprinting(void) const override;
private: private:
/** Xp Level stuff */
enum
{
XP_TO_LEVEL15 = 255,
XP_PER_LEVEL_TO15 = 17,
XP_TO_LEVEL30 = 825
} ;
typedef std::vector<std::vector<AString> > AStringVectorVector; typedef std::vector<std::vector<AString> > AStringVectorVector;
/** The current body stance the player has adopted. */
std::variant<BodyStanceCrouching, BodyStanceSleeping, BodyStanceSprinting, BodyStanceStanding, BodyStanceGliding> m_BodyStance;
/** The name of the rank assigned to this player. */ /** The name of the rank assigned to this player. */
AString m_Rank; AString m_Rank;
@ -599,16 +652,6 @@ private:
AString m_MsgPrefix, m_MsgSuffix; AString m_MsgPrefix, m_MsgSuffix;
AString m_MsgNameColorCode; AString m_MsgNameColorCode;
/** Xp Level stuff */
enum
{
XP_TO_LEVEL15 = 255,
XP_PER_LEVEL_TO15 = 17,
XP_TO_LEVEL30 = 825
} ;
bool m_bVisible;
// Food-related variables: // Food-related variables:
/** Represents the food bar, one point equals half a "drumstick" */ /** Represents the food bar, one point equals half a "drumstick" */
int m_FoodLevel; int m_FoodLevel;
@ -622,8 +665,6 @@ private:
/** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */ /** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */
double m_FoodExhaustionLevel; double m_FoodExhaustionLevel;
double m_Stance;
/** Stores the player's inventory, consisting of crafting grid, hotbar, and main slots */ /** Stores the player's inventory, consisting of crafting grid, hotbar, and main slots */
cInventory m_Inventory; cInventory m_Inventory;
@ -656,12 +697,6 @@ private:
cSlotNums m_InventoryPaintSlots; cSlotNums m_InventoryPaintSlots;
/** If true, we are locking m_Position to m_FrozenPosition. */
bool m_IsFrozen;
/** Was the player frozen manually by a plugin or automatically by the server? */
bool m_IsManuallyFrozen;
/** Max speed, relative to the game default. /** Max speed, relative to the game default.
1 means regular speed, 2 means twice as fast, 0.5 means half-speed. 1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
Default value is 1. */ Default value is 1. */
@ -677,12 +712,25 @@ private:
Default value is 1. */ Default value is 1. */
double m_FlyingMaxSpeed; double m_FlyingMaxSpeed;
bool m_IsCrouched; bool m_IsChargingBow;
bool m_IsSprinting;
bool m_IsFlying;
bool m_IsFishing; bool m_IsFishing;
bool m_CanFly; // If this is true the player can fly. Even if he is not in creative. /** If this is true the player can fly. Even if he is not in creative. */
bool m_IsFlightCapable;
bool m_IsFlying;
/** If true, we are locking m_Position to m_FrozenPosition. */
bool m_IsFrozen;
/** Was the player frozen manually by a plugin or automatically by the server? */
bool m_IsManuallyFrozen;
/** Flag used by food handling system to determine whether a teleport has just happened.
Will not apply food penalties if found to be true; will set to false after processing. */
bool m_IsTeleporting;
bool m_IsVisible;
/** The world tick in which eating will be finished. -1 if not eating */ /** The world tick in which eating will be finished. -1 if not eating */
Int64 m_EatingFinishTick; Int64 m_EatingFinishTick;
@ -692,8 +740,7 @@ private:
int m_CurrentXp; int m_CurrentXp;
unsigned int m_EnchantmentSeed; unsigned int m_EnchantmentSeed;
bool m_IsChargingBow; int m_BowCharge;
int m_BowCharge;
UInt32 m_FloaterID; UInt32 m_FloaterID;
@ -701,19 +748,10 @@ private:
cStatManager m_Stats; cStatManager m_Stats;
/** Flag representing whether the player is currently in a bed
Set by a right click on unoccupied bed, unset by a time fast forward or teleport */
bool m_bIsInBed;
/** How long till the player's inventory will be saved /** How long till the player's inventory will be saved
Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */ Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */
unsigned int m_TicksUntilNextSave; unsigned int m_TicksUntilNextSave;
/** Flag used by food handling system to determine whether a teleport has just happened
Will not apply food penalties if found to be true; will set to false after processing
*/
bool m_bIsTeleporting;
AString m_CustomName; AString m_CustomName;
/** Displayed skin part bit mask */ /** Displayed skin part bit mask */
@ -769,6 +807,7 @@ private:
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual float GetEnchantmentBlastKnockbackReduction() override; virtual float GetEnchantmentBlastKnockbackReduction() override;
virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); } virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); }
virtual bool IsRclking(void) const override { return IsEating() || IsChargingBow(); }
virtual void OnAddToWorld(cWorld & a_World) override; virtual void OnAddToWorld(cWorld & a_World) override;
virtual void OnRemoveFromWorld(cWorld & a_World) override; virtual void OnRemoveFromWorld(cWorld & a_World) override;
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;

View File

@ -133,6 +133,7 @@ short cItem::GetMaxDamage(void) const
case E_ITEM_DIAMOND_PICKAXE: return 1561; case E_ITEM_DIAMOND_PICKAXE: return 1561;
case E_ITEM_DIAMOND_SHOVEL: return 1561; case E_ITEM_DIAMOND_SHOVEL: return 1561;
case E_ITEM_DIAMOND_SWORD: return 1561; case E_ITEM_DIAMOND_SWORD: return 1561;
case E_ITEM_ELYTRA: return 432;
case E_ITEM_FLINT_AND_STEEL: return 64; case E_ITEM_FLINT_AND_STEEL: return 64;
case E_ITEM_FISHING_ROD: return 65; case E_ITEM_FISHING_ROD: return 65;
case E_ITEM_GOLD_AXE: return 32; case E_ITEM_GOLD_AXE: return 32;

View File

@ -63,14 +63,7 @@ public:
} }
a_Player->GetInventory().SetArmorSlot(SlotNum, a_HeldItem.CopyOne()); a_Player->GetInventory().SetArmorSlot(SlotNum, a_HeldItem.CopyOne());
a_Player->GetInventory().RemoveOneEquippedItem();
cItem Item(a_HeldItem);
Item.m_ItemCount--;
if (Item.m_ItemCount <= 0)
{
Item.Empty();
}
a_Player->GetInventory().SetEquippedItem(Item);
return true; return true;
} }
@ -110,6 +103,7 @@ public:
{ {
return (a_ItemType == E_ITEM_GOLD); return (a_ItemType == E_ITEM_GOLD);
} }
case E_ITEM_ELYTRA: // TODO: require Phantom Membrane instead of leather starting from protocol version 369 or 1.13 release
case E_ITEM_LEATHER_BOOTS: case E_ITEM_LEATHER_BOOTS:
case E_ITEM_LEATHER_CAP: case E_ITEM_LEATHER_CAP:
case E_ITEM_LEATHER_PANTS: case E_ITEM_LEATHER_PANTS:

View File

@ -282,6 +282,7 @@ cItemHandler * cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_RABBIT_STEW: return new cItemSoupHandler(a_ItemType, FoodInfo(10, 12)); case E_ITEM_RABBIT_STEW: return new cItemSoupHandler(a_ItemType, FoodInfo(10, 12));
// Armor: // Armor:
case E_ITEM_ELYTRA:
case E_ITEM_LEATHER_CAP: case E_ITEM_LEATHER_CAP:
case E_ITEM_GOLD_HELMET: case E_ITEM_GOLD_HELMET:
case E_ITEM_CHAIN_HELMET: case E_ITEM_CHAIN_HELMET:

View File

@ -349,6 +349,10 @@ void cProtocol_1_12::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_
{ {
Flags |= 0x20; Flags |= 0x20;
} }
if (a_Entity.IsElytraFlying())
{
Flags |= 0x80;
}
a_Pkt.WriteBEUInt8(ENTITY_FLAGS); // Index a_Pkt.WriteBEUInt8(ENTITY_FLAGS); // Index
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
a_Pkt.WriteBEInt8(Flags); a_Pkt.WriteBEInt8(Flags);

View File

@ -2462,14 +2462,20 @@ void cProtocol_1_8_0::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action); HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action);
HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost); HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost);
if (PlayerID != m_Client->GetPlayer()->GetUniqueID())
{
m_Client->Kick("Mind your own business! Hacked client?");
return;
}
switch (Action) switch (Action)
{ {
case 0: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch case 0: return m_Client->HandleCrouch(true);
case 1: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch case 1: return m_Client->HandleCrouch(false);
case 2: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed case 2: return m_Client->HandleLeaveBed();
case 3: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting case 3: return m_Client->HandleSprint(true);
case 4: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting case 4: return m_Client->HandleSprint(false);
case 6: m_Client->HandleOpenHorseInventory(PlayerID); break; // Open horse inventory case 6: return m_Client->HandleOpenHorseInventory();
} }
} }
@ -2535,7 +2541,7 @@ void cProtocol_1_8_0::HandlePacketPlayerPos(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY); HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY);
HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ); HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ);
HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround); HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
m_Client->HandlePlayerPos(PosX, PosY, PosZ, PosY + (m_Client->GetPlayer()->IsCrouched() ? 1.54 : 1.62), IsOnGround); m_Client->HandlePlayerPos(PosX, PosY, PosZ, IsOnGround);
} }
@ -2550,7 +2556,7 @@ void cProtocol_1_8_0::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Yaw); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Yaw);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Pitch); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Pitch);
HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround); HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, PosY + 1.62, Yaw, Pitch, IsOnGround); m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, Yaw, Pitch, IsOnGround);
} }
@ -3355,6 +3361,10 @@ void cProtocol_1_8_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a
{ {
Flags |= 0x20; Flags |= 0x20;
} }
if (a_Entity.IsElytraFlying())
{
Flags |= 0x80;
}
a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0 a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0
a_Pkt.WriteBEUInt8(Flags); a_Pkt.WriteBEUInt8(Flags);

View File

@ -945,14 +945,21 @@ void cProtocol_1_9_0::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action); HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action);
HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost); HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost);
if (PlayerID != m_Client->GetPlayer()->GetUniqueID())
{
m_Client->Kick("Mind your own business! Hacked client?");
return;
}
switch (Action) switch (Action)
{ {
case 0: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch case 0: return m_Client->HandleCrouch(true);
case 1: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch case 1: return m_Client->HandleCrouch(false);
case 2: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed case 2: return m_Client->HandleLeaveBed();
case 3: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting case 3: return m_Client->HandleSprint(true);
case 4: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting case 4: return m_Client->HandleSprint(false);
case 7: m_Client->HandleOpenHorseInventory(PlayerID); break; // Open horse inventory case 7: return m_Client->HandleOpenHorseInventory();
case 8: return m_Client->HandleStartElytraFlight();
} }
} }
@ -969,7 +976,7 @@ void cProtocol_1_9_0::HandlePacketPlayerPos(cByteBuffer & a_ByteBuffer)
if (m_IsTeleportIdConfirmed) if (m_IsTeleportIdConfirmed)
{ {
m_Client->HandlePlayerPos(PosX, PosY, PosZ, PosY + (m_Client->GetPlayer()->IsCrouched() ? 1.54 : 1.62), IsOnGround); m_Client->HandlePlayerPos(PosX, PosY, PosZ, IsOnGround);
} }
} }
@ -988,7 +995,7 @@ void cProtocol_1_9_0::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer)
if (m_IsTeleportIdConfirmed) if (m_IsTeleportIdConfirmed)
{ {
m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, PosY + 1.62, Yaw, Pitch, IsOnGround); m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, Yaw, Pitch, IsOnGround);
} }
} }
@ -1666,6 +1673,10 @@ void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a
{ {
Flags |= 0x20; Flags |= 0x20;
} }
if (a_Entity.IsElytraFlying())
{
Flags |= 0x80;
}
a_Pkt.WriteBEUInt8(0); // Index 0 a_Pkt.WriteBEUInt8(0); // Index 0
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
a_Pkt.WriteBEInt8(Flags); a_Pkt.WriteBEInt8(Flags);

View File

@ -33,16 +33,7 @@ class cPlayer;
class cClientHandle; class cClientHandle;
class cEntity; class cEntity;
class cChunkGenerator; // The thread responsible for generating chunks class cChunkGenerator; // The thread responsible for generating chunks
class cBeaconEntity;
class cBrewingstandEntity;
class cChestEntity;
class cCuboid; class cCuboid;
class cDispenserEntity;
class cFlowerPotEntity;
class cFurnaceEntity;
class cHopperEntity;
class cNoteEntity;
class cMobHeadEntity;
class cCompositeChat; class cCompositeChat;
class cDeadlockDetect; class cDeadlockDetect;
class cUUID; class cUUID;