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",
},
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 =
{
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.",
},
GetStance =
{
Returns =
{
{
Type = "number",
},
},
Notes = "Returns the player's stance (Y-pos of player's eyes)",
},
GetTeam =
{
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.",
},
SetElytraFlight =
{
Params =
{
{
Name = "IsElytraFlying",
Type = "boolean",
},
},
Notes = "Sets whether the player is elytra flying or not.",
},
SetSprintingMaxSpeed =
{
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)
{
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())
{
@ -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 OldPosition = GetPlayer()->GetPosition();
double OldStance = GetPlayer()->GetStance();
auto PreviousIsOnGround = GetPlayer()->IsOnGround();
#ifdef __clang__
@ -769,7 +774,6 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
if (
(OldPosition == NewPosition) &&
(OldStance == a_Stance) &&
(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
m_Player->SetPosition(NewPosition);
m_Player->SetStance(a_Stance);
m_Player->SetTouchGround(a_IsOnGround);
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);
}
@ -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)
{
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())
{
// We should only receive entity actions from the entity that is performing the action
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);
cChunkInterface Interface(m_Player->GetWorld()->GetChunkMap());
cBlockBedHandler::SetBedOccupationState(Interface, m_Player->GetLastBedPos(), false);
m_Player->SetIsInBed(false);
}

View File

@ -322,13 +322,12 @@ public: // tolua_export
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);
/** Handles a player sneaking or unsneaking. */
void HandleCrouch(bool a_IsCrouching);
/** Called when the player enchants an Item in the Enchanting table UI. */
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.
Returns false if the client has been kicked, true otherwise. */
bool CheckMultiLogin(const AString & a_Username);
@ -339,6 +338,9 @@ public: // tolua_export
*/
bool HandleHandshake (const AString & a_Username);
/** Handles a player exiting his bed. */
void HandleLeaveBed();
void HandleKeepAlive (UInt32 a_KeepAliveID);
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. */
void HandleNPCTrade(int a_SlotNum);
/** Handles a player opening their 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(UInt32 a_EntityID);
/** Handles a player opening his inventory while riding a horse. */
void HandleOpenHorseInventory();
void HandlePing (void);
void HandlePlayerAbilities (bool a_IsFlying, float FlyingSpeed, float WalkingSpeed);
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
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
*/
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);
@ -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 HandleSlotSelected (Int16 a_SlotNum);
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 HandleTabCompletion (const AString & a_Text);
void HandleUpdateSign (

View File

@ -535,6 +535,7 @@ bool ItemCategory::IsHelmet(short a_ItemType)
bool ItemCategory::IsChestPlate(short a_ItemType)
{
return (
(a_ItemType == E_ITEM_ELYTRA) ||
(a_ItemType == E_ITEM_LEATHER_TUNIC) ||
(a_ItemType == E_ITEM_GOLD_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_IsInWater(false),
m_IsHeadInWater(false),
m_Width(a_Width),
m_Height(a_Height),
m_AirLevel(MAX_AIR_LEVEL),
m_AirTickTimer(DROWNING_TICKS),
m_TicksAlive(0),
@ -69,8 +71,6 @@ cEntity::cEntity(eEntityType a_EntityType, Vector3d a_Pos, double a_Width, doubl
m_Position(a_Pos),
m_WaterSpeed(0, 0, 0),
m_Mass (0.001), // Default 1g
m_Width(a_Width),
m_Height(a_Height),
m_InvulnerableTicks(0)
{
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)
{
// 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)
{
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
void SetHeight(double a_Height);
void SetWidth(double a_Width);
/** Exported in ManualBindings */
const Vector3d & GetPosition(void) const { return m_Position; }
@ -522,12 +518,13 @@ public:
// tolua_begin
// 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 IsRiding (void) const {return false; }
virtual bool IsSprinting(void) const {return false; }
virtual bool IsRclking (void) const {return false; }
virtual bool IsInvisible(void) const { return false; }
virtual bool IsCrouched (void) const { return false; }
virtual bool IsElytraFlying(void) const { return false; }
virtual bool IsInvisible (void) const { return false; }
virtual bool IsOnFire (void) const { return m_TicksLeftBurning > 0; }
virtual bool IsRclking (void) const { return false; }
virtual bool IsRiding (void) const { return false; }
virtual bool IsSprinting (void) const { return false; }
/** Returns true if any part of the entity is in a fire block */
virtual bool IsInFire(void) const { return m_IsInFire; }
@ -689,6 +686,12 @@ protected:
/** If the entity's head is in a water block */
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 */
int m_AirLevel;
int m_AirTickTimer;
@ -745,12 +748,6 @@ private:
/** Measured in Kilograms (Kg) */
double m_Mass;
/** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */
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.
While this ticks, a player can't hit this entity. */
int m_InvulnerableTicks;

View File

@ -106,8 +106,6 @@ cMinecart::cMinecart(ePayload a_Payload, Vector3d a_Pos):
SetAirDrag(0.05f);
SetMaxHealth(6);
SetHealth(6);
SetWidth(1);
SetHeight(0.9);
}
@ -1274,10 +1272,10 @@ void cMinecart::ApplyAcceleration(Vector3d a_ForwardDirection, double a_Accelera
////////////////////////////////////////////////////////////////////////////////
// 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),
m_Content(a_Content),
m_Height(a_Height)
m_ContentHeight(a_ContentHeight)
{
}

View File

@ -105,10 +105,10 @@ public:
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;}
int GetBlockHeight(void) const {return m_Height;}
const cItem & GetContent(void) const { return m_Content; }
int GetBlockHeight(void) const { return m_ContentHeight; }
// cEntity overrides:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
@ -116,9 +116,8 @@ public:
protected:
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);
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);
// 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) :
Super(etPlayer, 0.6, 1.8),
m_bVisible(true),
m_BodyStance(BodyStanceStanding(*this)),
m_FoodLevel(MAX_FOOD_LEVEL),
m_FoodSaturationLevel(5.0),
m_FoodTickTimer(0),
m_FoodExhaustionLevel(0.0),
m_Stance(0.0),
m_Inventory(*this),
m_EnderChestContents(9, 3),
m_DefaultWorldPath(cRoot::Get()->GetDefaultWorld()->GetDataPath()),
m_GameMode(eGameMode_NotSet),
m_ClientHandle(a_Client),
m_IsFrozen(false),
m_NormalMaxSpeed(1.0),
m_SprintingMaxSpeed(1.3),
m_FlyingMaxSpeed(1.0),
m_IsCrouched(false),
m_IsSprinting(false),
m_IsFlying(false),
m_IsChargingBow(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_LifetimeTotalXp(0),
m_CurrentXp(0),
m_IsChargingBow(false),
m_BowCharge(0),
m_FloaterID(cEntity::INVALID_ID),
m_Team(nullptr),
m_bIsInBed(false),
m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL),
m_bIsTeleporting(false),
m_SkinParts(0),
m_MainHand(mhRight)
{
@ -114,26 +148,25 @@ cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) :
LoadFromDisk(World);
m_LastGroundHeight = static_cast<float>(GetPosY());
m_Stance = GetPosY() + 1.62;
if (m_GameMode == gmNotSet)
{
if (World->IsGameModeCreative())
{
m_CanFly = true;
m_IsFlightCapable = true;
}
if (World->IsGameModeSpectator()) // Otherwise Player will fall out of the world on join
{
m_CanFly = true;
m_IsFlightCapable = true;
m_IsFlying = true;
}
}
if (m_GameMode == gmSpectator) // If player is reconnecting to the server in spectator mode
{
m_CanFly = true;
m_IsFlightCapable = 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)
{
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)
{
// Set the timer:
@ -525,11 +593,11 @@ const cSlotNums & cPlayer::GetInventoryPaintSlots(void) const
double cPlayer::GetMaxSpeed(void) const
{
if (m_IsFlying)
if (IsFlying())
{
return m_FlyingMaxSpeed;
}
else if (m_IsSprinting)
else if (IsSprinting())
{
return m_SprintingMaxSpeed;
}
@ -546,7 +614,7 @@ double cPlayer::GetMaxSpeed(void) const
void cPlayer::SetNormalMaxSpeed(double 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
m_ClientHandle->SendPlayerMaxSpeed();
@ -560,7 +628,7 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
void cPlayer::SetSprintingMaxSpeed(double 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
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_IsCrouched == m_IsCrouched)
{
// No change
return;
}
if (a_IsCrouched)
if (a_ShouldCrouch && IsStanding())
{
m_BodyStance = BodyStanceCrouching(*this);
cRoot::Get()->GetPluginManager()->CallHookPlayerCrouched(*this);
}
else if (!a_ShouldCrouch && IsCrouched())
{
m_BodyStance = BodyStanceStanding(*this);
}
m_IsCrouched = a_IsCrouched;
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;
}
m_IsSprinting = a_IsSprinting;
m_ClientHandle->SendPlayerMaxSpeed();
m_IsFlying = a_ShouldFly;
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)
{
if (a_CanFly == m_CanFly)
if (a_CanFly == m_IsFlightCapable)
{
return;
}
m_CanFly = a_CanFly;
m_IsFlightCapable = a_CanFly;
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)
{
ASSERT(a_Opponent != nullptr);
@ -750,7 +835,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI)
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
// that the player is attached to the entity / object
@ -905,7 +990,7 @@ void cPlayer::Respawn(void)
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
{
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});
FreezeInternal(GetPosition(), false);
m_bIsTeleporting = true;
m_IsTeleporting = true;
m_ClientHandle->SendPlayerMoveLook();
}
@ -1344,6 +1444,11 @@ bool cPlayer::IsFrozen()
void cPlayer::Unfreeze()
{
if (IsElytraFlying())
{
m_World->BroadcastEntityMetadata(*this);
}
GetClientHandle()->SendPlayerAbilities();
GetClientHandle()->SendPlayerMaxSpeed();
@ -1449,14 +1554,14 @@ void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
void cPlayer::SetVisible(bool a_bVisible)
{
// 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);
}
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
}
}
@ -1809,7 +1914,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
if (m_GameMode == eGameMode_Creative)
{
m_CanFly = true;
m_IsFlightCapable = true;
}
m_Inventory.LoadFromJson(Root["inventory"]);
@ -2141,9 +2246,9 @@ bool cPlayer::IsClimbing(void) const
void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround)
{
if (m_bIsTeleporting)
if (m_IsTeleporting)
{
m_bIsTeleporting = false;
m_IsTeleporting = false;
return;
}
@ -2599,16 +2704,19 @@ float cPlayer::GetLiquidHeightPercent(NIBBLETYPE a_Meta)
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))
{
return false;
}
NIBBLETYPE Meta = GetWorld()->GetBlockMeta(Vector3d(GetPosX(), m_Stance, GetPosZ()).Floor());
const auto EyeHeight = GetEyeHeight();
float f = GetLiquidHeightPercent(Meta) - 0.11111111f;
float f1 = static_cast<float>(m_Stance + 1) - f;
bool flag = (m_Stance < f1);
return flag;
float f1 = static_cast<float>(EyeHeight + 1) - f;
return EyeHeight < f1;
}
@ -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)
{
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)
{
Super::OnAddToWorld(a_World);
@ -3023,7 +3168,7 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
void cPlayer::SpawnOn(cClientHandle & a_Client)
{
if (!m_bVisible || (m_ClientHandle.get() == (&a_Client)))
if (!m_IsVisible || (m_ClientHandle.get() == (&a_Client)))
{
return;
}
@ -3110,6 +3255,27 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
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());
if (m_Health > 0) // make sure player is alive

View File

@ -27,11 +27,57 @@ class cTeam;
class cPlayer:
public cPawn
{
// tolua_end
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
public:
@ -105,11 +151,8 @@ public:
bool IsChargingBow(void) const { return m_IsChargingBow; }
void SetTouchGround(bool a_bTouchGround);
inline void SetStance(const double a_Stance) { m_Stance = a_Stance; }
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 m_Stance; } // tolua_export
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
inline const cInventory & GetInventory(void) const { return m_Inventory; }
@ -333,8 +376,8 @@ public:
/** Returns true if the player is currently flying */
bool IsFlying(void) const { return m_IsFlying; }
/** Returns true if a player is sleeping in a bed */
bool IsInBed(void) const { return m_bIsInBed; }
/** Returns true if a player is sleeping in a bed. */
bool IsInBed(void) const;
/** Returns true if the player has thrown out a floater */
bool IsFishing(void) const { return m_IsFishing; }
@ -345,21 +388,16 @@ public:
// tolua_end
/** Returns true if a player is standing normally, that is, in a neutral pose. */
bool IsStanding() const;
/** Tosses a list of items. */
void TossItems(const cItems & a_Items);
/** Sets a player's in-bed state
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
*/
void SetIsInBed(bool a_Flag)
{
m_bIsInBed = a_Flag;
if (!a_Flag)
{
GetWorld()->BroadcastEntityAnimation(*this, 2);
}
}
/** Sets a player's in-bed state.
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. */
void SetIsInBed(bool a_IsInBed);
/** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
void StartEating(void);
@ -377,7 +415,7 @@ public:
void Respawn(void); // 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. */
void SaveToDisk(void);
@ -450,14 +488,17 @@ public:
/** 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 crouching, if our current body stance permits, broadcasting the state change. */
void SetCrouch(bool a_ShouldCrouch);
/** Starts or stops sprinting, sends the max speed update to the client, if needed */
void SetSprint(bool a_IsSprinting);
/** Starts or stops elytra flight, if our current body stance permits, broadcasting the state change. */
void SetElytraFlight(bool a_ShouldElytraFly);
/** Flags the player as flying */
void SetFlying(bool a_IsFlying);
/** Starts or stops flying, broadcasting the state change. */
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. */
void SetCanFly(bool a_CanFly);
@ -501,7 +542,7 @@ public:
// tolua_begin
/** 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.
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);
// 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
(1 would be completely mined)
Depends on hardness values so check those are correct.
@ -565,18 +598,38 @@ public:
If the item is already known, does nothing. */
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:
virtual void AttachTo(cEntity * a_AttachTo) override;
virtual void Detach(void) override;
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); }
virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); }
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
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:
/** Xp Level stuff */
enum
{
XP_TO_LEVEL15 = 255,
XP_PER_LEVEL_TO15 = 17,
XP_TO_LEVEL30 = 825
} ;
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. */
AString m_Rank;
@ -599,16 +652,6 @@ private:
AString m_MsgPrefix, m_MsgSuffix;
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:
/** Represents the food bar, one point equals half a "drumstick" */
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 */
double m_FoodExhaustionLevel;
double m_Stance;
/** Stores the player's inventory, consisting of crafting grid, hotbar, and main slots */
cInventory m_Inventory;
@ -656,12 +697,6 @@ private:
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.
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
Default value is 1. */
@ -677,12 +712,25 @@ private:
Default value is 1. */
double m_FlyingMaxSpeed;
bool m_IsCrouched;
bool m_IsSprinting;
bool m_IsFlying;
bool m_IsChargingBow;
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 */
Int64 m_EatingFinishTick;
@ -692,8 +740,7 @@ private:
int m_CurrentXp;
unsigned int m_EnchantmentSeed;
bool m_IsChargingBow;
int m_BowCharge;
int m_BowCharge;
UInt32 m_FloaterID;
@ -701,19 +748,10 @@ private:
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
Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */
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;
/** Displayed skin part bit mask */
@ -769,6 +807,7 @@ private:
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual float GetEnchantmentBlastKnockbackReduction() override;
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 OnRemoveFromWorld(cWorld & a_World) 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_SHOVEL: 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_FISHING_ROD: return 65;
case E_ITEM_GOLD_AXE: return 32;

View File

@ -63,14 +63,7 @@ public:
}
a_Player->GetInventory().SetArmorSlot(SlotNum, a_HeldItem.CopyOne());
cItem Item(a_HeldItem);
Item.m_ItemCount--;
if (Item.m_ItemCount <= 0)
{
Item.Empty();
}
a_Player->GetInventory().SetEquippedItem(Item);
a_Player->GetInventory().RemoveOneEquippedItem();
return true;
}
@ -110,6 +103,7 @@ public:
{
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_CAP:
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));
// Armor:
case E_ITEM_ELYTRA:
case E_ITEM_LEATHER_CAP:
case E_ITEM_GOLD_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;
}
if (a_Entity.IsElytraFlying())
{
Flags |= 0x80;
}
a_Pkt.WriteBEUInt8(ENTITY_FLAGS); // Index
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
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, ReadVarInt, UInt32, JumpBoost);
if (PlayerID != m_Client->GetPlayer()->GetUniqueID())
{
m_Client->Kick("Mind your own business! Hacked client?");
return;
}
switch (Action)
{
case 0: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch
case 1: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch
case 2: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
case 3: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
case 4: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
case 6: m_Client->HandleOpenHorseInventory(PlayerID); break; // Open horse inventory
case 0: return m_Client->HandleCrouch(true);
case 1: return m_Client->HandleCrouch(false);
case 2: return m_Client->HandleLeaveBed();
case 3: return m_Client->HandleSprint(true);
case 4: return m_Client->HandleSprint(false);
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, PosZ);
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, Pitch);
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;
}
if (a_Entity.IsElytraFlying())
{
Flags |= 0x80;
}
a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0
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, ReadVarInt, UInt32, JumpBoost);
if (PlayerID != m_Client->GetPlayer()->GetUniqueID())
{
m_Client->Kick("Mind your own business! Hacked client?");
return;
}
switch (Action)
{
case 0: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch
case 1: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch
case 2: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
case 3: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
case 4: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
case 7: m_Client->HandleOpenHorseInventory(PlayerID); break; // Open horse inventory
case 0: return m_Client->HandleCrouch(true);
case 1: return m_Client->HandleCrouch(false);
case 2: return m_Client->HandleLeaveBed();
case 3: return m_Client->HandleSprint(true);
case 4: return m_Client->HandleSprint(false);
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)
{
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)
{
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;
}
if (a_Entity.IsElytraFlying())
{
Flags |= 0x80;
}
a_Pkt.WriteBEUInt8(0); // Index 0
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
a_Pkt.WriteBEInt8(Flags);

View File

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