summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Blocks/BlockBed.cpp109
-rw-r--r--src/Blocks/BlockBed.h45
-rw-r--r--src/ClientHandle.cpp3
-rw-r--r--src/Entities/Player.cpp11
4 files changed, 88 insertions, 80 deletions
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index 4fe22dffd..68f45b518 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -60,11 +60,13 @@ bool cBlockBedHandler::OnUse(
cChunkInterface & a_ChunkInterface,
cWorldInterface & a_WorldInterface,
cPlayer & a_Player,
- const Vector3i a_BlockPos,
+ Vector3i a_BlockPos,
eBlockFace a_BlockFace,
const Vector3i a_CursorPos
) const
{
+ // Source: https://minecraft.gamepedia.com/Bed#Sleeping
+
// Sleeping in bed only allowed in Overworld, beds explode elsewhere:
if (a_WorldInterface.GetDimension() != dimOverworld)
{
@@ -73,82 +75,82 @@ bool cBlockBedHandler::OnUse(
return true;
}
+ auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
+
+ if ((Meta & 0x8) == 0)
+ {
+ // Clicked on the foot of the bed, adjust to the head:
+ a_BlockPos += MetaDataToDirection(Meta & 0x03);
+
+ BLOCKTYPE Type;
+ a_ChunkInterface.GetBlockTypeMeta(a_BlockPos, Type, Meta);
+ if (Type != E_BLOCK_BED)
+ {
+ // Bed was incomplete, bail:
+ return true;
+ }
+ }
+
+ // Set the bed position to the pillow block:
+ a_Player.SetBedPos(a_BlockPos);
+
// Sleeping is allowed only during night and thunderstorms:
if (
!(((a_WorldInterface.GetTimeOfDay() > 12541_tick) && (a_WorldInterface.GetTimeOfDay() < 23458_tick)) ||
(a_Player.GetWorld()->GetWeather() == wThunderstorm))
- ) // Source: https://minecraft.gamepedia.com/Bed#Sleeping
+ )
{
a_Player.SendAboveActionBarMessage("You can only sleep at night and during thunderstorms");
-
- // Try to set home position anyway:
- SetBedPos(a_Player, a_BlockPos);
return true;
}
// Check if the bed is occupied:
- auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
if ((Meta & 0x04) == 0x04)
{
- a_Player.SendMessageFailure("This bed is occupied");
+ a_Player.SendAboveActionBarMessage("This bed is occupied");
return true;
}
// Cannot sleep if there are hostile mobs nearby:
- auto FindMobs = [](cEntity & a_Entity)
- {
- return (
- (a_Entity.GetEntityType() == cEntity::etMonster) &&
- (static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile)
- );
- };
- if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs))
+ if (
+ !a_Player.GetWorld()->ForEachEntityInBox({ a_Player.GetPosition().addedY(-5), 8, 10 }, [](cEntity & a_Entity)
+ {
+ return a_Entity.IsMob() && (static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile);
+ })
+ )
{
a_Player.SendAboveActionBarMessage("You may not rest now, there are monsters nearby");
return true;
}
- // Broadcast the "Use bed" for the pillow block:
- if ((Meta & 0x8) == 0x8)
- {
- // Is pillow
- a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, a_BlockPos);
- }
- else
- {
- // Is foot end
- VERIFY((Meta & 0x04) != 0x04); // Occupied flag should never be set, else our compilator (intended) is broken
+ // This will broadcast "use bed" for the pillow block, if the player can sleep:
+ a_Player.SetIsInBed(true);
- auto PillowPos = a_BlockPos + MetaDataToDirection(Meta & 0x03);
- if (a_ChunkInterface.GetBlock(PillowPos) == E_BLOCK_BED) // Must always use pillow location for sleeping
- {
- a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, PillowPos);
- }
+ // Check sleeping was successful, if not, bail:
+ if (!a_Player.IsInBed())
+ {
+ return true;
}
- // Occupy the bed:
- SetBedPos(a_Player, a_BlockPos);
- SetBedOccupationState(a_ChunkInterface, a_Player.GetLastBedPos(), true);
- a_Player.SetIsInBed(true);
+ // Occupy the bed, where 0x4 = occupied bit:
+ a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta | 0x04);
a_Player.GetStatManager().AddValue(Statistic::SleepInBed);
+ // When sleeping, the player's bounding box moves to approximately where his head is.
+ // Set the player's position to somewhere close to the edge of the pillow block:
+ a_Player.SetPosition(Vector3f(0.4f, 1, 0.4f) * MetaDataToDirection(Meta & 0x03) + Vector3f(0.5f, 0.6875, 0.5f) + a_BlockPos);
+
// Fast-forward the time if all players in the world are in their beds:
- auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer)
- {
- return !a_OtherPlayer.IsInBed();
- };
- if (a_WorldInterface.ForEachPlayer(TimeFastForwardTester))
+ if (a_WorldInterface.ForEachPlayer([](cPlayer & a_OtherPlayer) { return !a_OtherPlayer.IsInBed(); }))
{
- a_WorldInterface.ForEachPlayer([&](cPlayer & a_OtherPlayer)
- {
- cBlockBedHandler::SetBedOccupationState(a_ChunkInterface, a_OtherPlayer.GetLastBedPos(), false);
- a_OtherPlayer.SetIsInBed(false);
- return false;
- }
- );
+ a_WorldInterface.ForEachPlayer([&a_ChunkInterface](cPlayer & a_OtherPlayer)
+ {
+ VacateBed(a_ChunkInterface, a_OtherPlayer);
+ return false;
+ });
a_WorldInterface.SetTimeOfDay(0_tick);
- a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
}
+
return true;
}
@@ -175,16 +177,3 @@ cItems cBlockBedHandler::ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cI
// Drops handled by the block entity:
return {};
}
-
-
-
-
-
-void cBlockBedHandler::SetBedPos(cPlayer & a_Player, const Vector3i a_BedPosition)
-{
- if (a_Player.GetLastBedPos() != a_BedPosition)
- {
- a_Player.SetBedPos(a_BedPosition);
- a_Player.SendMessageSuccess("Home position set successfully");
- }
-}
diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h
index 1765773d6..7da6740bd 100644
--- a/src/Blocks/BlockBed.h
+++ b/src/Blocks/BlockBed.h
@@ -36,19 +36,40 @@ public:
return Vector3i();
}
- static void SetBedOccupationState(cChunkInterface & a_ChunkInterface, Vector3i a_BedPosition, bool a_IsOccupied)
+ static void VacateBed(cChunkInterface & a_ChunkInterface, cPlayer & a_Player)
{
- auto Meta = a_ChunkInterface.GetBlockMeta(a_BedPosition);
- if (a_IsOccupied)
+ auto BedPosition = a_Player.GetLastBedPos();
+
+ BLOCKTYPE Type;
+ NIBBLETYPE Meta;
+ a_ChunkInterface.GetBlockTypeMeta(BedPosition, Type, Meta);
+
+ if (Type != E_BLOCK_BED)
{
- Meta |= 0x04; // Where 0x4 = occupied bit
+ // Bed was incomplete, just wake:
+ a_Player.SetIsInBed(false);
+ return;
}
- else
+
+ if ((Meta & 0x8) == 0)
{
- Meta &= 0x0b; // Clear the "occupied" bit of the bed's block
+ // BedPosition is the foot of the bed, adjust to the head:
+ BedPosition += MetaDataToDirection(Meta & 0x03);
+
+ a_ChunkInterface.GetBlockTypeMeta(BedPosition, Type, Meta);
+ if (Type != E_BLOCK_BED)
+ {
+ // Bed was incomplete, just wake:
+ a_Player.SetIsInBed(false);
+ return;
+ }
}
- a_ChunkInterface.SetBlockMeta(a_BedPosition, Meta);
+ // Clear the "occupied" bit of the bed's pillow block:
+ a_ChunkInterface.SetBlockMeta(BedPosition, Meta & 0x0b);
+
+ // Wake the player:
+ a_Player.SetIsInBed(false);
}
private:
@@ -79,19 +100,9 @@ private:
- static void SetBedPos(cPlayer & a_Player, const Vector3i a_BedPosition);
-
-
-
-
-
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
{
UNUSED(a_Meta);
return 28;
}
} ;
-
-
-
-
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index d356b524a..1a99fa300 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1857,8 +1857,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
void cClientHandle::HandleLeaveBed()
{
cChunkInterface Interface(m_Player->GetWorld()->GetChunkMap());
- cBlockBedHandler::SetBedOccupationState(Interface, m_Player->GetLastBedPos(), false);
- m_Player->SetIsInBed(false);
+ cBlockBedHandler::VacateBed(Interface, *m_Player);
}
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 563a1cb97..f5752ffb4 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -481,11 +481,12 @@ void cPlayer::SetIsInBed(const bool a_GoToBed)
if (a_GoToBed && IsStanding())
{
m_BodyStance = BodyStanceSleeping(*this);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::PlayerEntersBed);
}
else if (!a_GoToBed && IsInBed())
{
m_BodyStance = BodyStanceStanding(*this);
- GetWorld()->BroadcastEntityAnimation(*this, 2);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::PlayerLeavesBed);
}
}
@@ -3252,6 +3253,14 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
SetElytraFlight(false);
}
}
+ else if (IsInBed())
+ {
+ // Check if sleeping is still possible:
+ if ((GetPosition().Floor() != m_LastBedPos) || (m_World->GetBlock(m_LastBedPos) != E_BLOCK_BED))
+ {
+ m_ClientHandle->HandleLeaveBed();
+ }
+ }
BroadcastMovementUpdate(m_ClientHandle.get());