From 071b7be3d4d08c337c01de7abca034e6c3746194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Imrich?= Date: Sat, 3 Apr 2021 19:45:20 +0200 Subject: [PATCH] Basic elytra flight (#5124) * Basic elytra flight Co-authored-by: 12xx12 <44411062+12xx12@users.noreply.github.com> Co-authored-by: Tiger Wang --- Server/Plugins/APIDump/APIDesc.lua | 31 ++- src/ClientHandle.cpp | 87 ++++---- src/ClientHandle.h | 26 ++- src/Defines.cpp | 1 + src/Entities/Entity.cpp | 22 +- src/Entities/Entity.h | 29 ++- src/Entities/Minecart.cpp | 6 +- src/Entities/Minecart.h | 9 +- src/Entities/Pawn.cpp | 5 + src/Entities/Player.cpp | 310 ++++++++++++++++++++++------- src/Entities/Player.h | 173 +++++++++------- src/Item.cpp | 1 + src/Items/ItemArmor.h | 10 +- src/Items/ItemHandler.cpp | 1 + src/Protocol/Protocol_1_12.cpp | 4 + src/Protocol/Protocol_1_8.cpp | 26 ++- src/Protocol/Protocol_1_9.cpp | 27 ++- src/World.h | 9 - 18 files changed, 490 insertions(+), 287 deletions(-) diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index ae6e4e0fb..3fba7a37b 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -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 = diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 61370ca4f..cd45068ee 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -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); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 39433f3a1..a72692266 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -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 ( diff --git a/src/Defines.cpp b/src/Defines.cpp index 4adbc1c5c..02b9f28d5 100644 --- a/src/Defines.cpp +++ b/src/Defines.cpp @@ -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) || diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index f1d8c989d..a6f7dd58c 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -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); diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 9fe7f16f5..559f4eb66 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -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; diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 5fc67db5a..c4636c5b1 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -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) { } diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index a98014799..0d62d98f1 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -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; } ; diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp index 6f33a5eca..a58c1dc40 100644 --- a/src/Entities/Pawn.cpp +++ b/src/Entities/Pawn.cpp @@ -418,6 +418,11 @@ void cPawn::HandleFalling(void) auto Damage = static_cast(m_LastGroundHeight - GetPosY() - 3.0); if ((Damage > 0) && !FallDamageAbsorbed) { + if (IsElytraFlying()) + { + Damage = static_cast(static_cast(Damage) * 0.33); + } + TakeDamage(dtFalling, nullptr, Damage, static_cast(Damage), 0); // Fall particles diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 9497d326b..a727429d4 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -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 & 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 & a_Client) : LoadFromDisk(World); m_LastGroundHeight = static_cast(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(m_BodyStance); +} + + + + + +bool cPlayer::IsStanding() const +{ + return std::holds_alternative(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(m_Stance + 1) - f; - bool flag = (m_Stance < f1); - return flag; + float f1 = static_cast(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(m_BodyStance); +} + + + + + +bool cPlayer::IsElytraFlying(void) const +{ + return std::holds_alternative(m_BodyStance); +} + + + + + +bool cPlayer::IsSprinting(void) const +{ + return std::holds_alternative(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(m_BodyStance).TicksElytraFlying; + const auto TotalFlew = TicksFlying + a_Dt; + const auto Periods = static_cast(TotalFlew / 1s); + TicksFlying = std::chrono::duration_cast(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 diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 4d6a41a35..5a17ca783 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -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 > AStringVectorVector; + /** The current body stance the player has adopted. */ + std::variant 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; diff --git a/src/Item.cpp b/src/Item.cpp index 7950731c0..a6a464450 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -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; diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h index d91888d5b..3139c09f4 100644 --- a/src/Items/ItemArmor.h +++ b/src/Items/ItemArmor.h @@ -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: diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 8c970692f..bfeba1373 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -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: diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp index 81f81dc1c..06238e408 100644 --- a/src/Protocol/Protocol_1_12.cpp +++ b/src/Protocol/Protocol_1_12.cpp @@ -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); diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index fe99ab91a..7d4dfb85d 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -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); diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 0669e6a1a..0827b8f0b 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -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); diff --git a/src/World.h b/src/World.h index 9bb1f8b6b..feed6a216 100644 --- a/src/World.h +++ b/src/World.h @@ -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;