Skip to content

Commit

Permalink
Handle client 'leave bed' request
Browse files Browse the repository at this point in the history
* Fixes #1728
  • Loading branch information
tigerw committed Feb 8, 2015
1 parent 1ce9164 commit 3869f76
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 61 deletions.
27 changes: 10 additions & 17 deletions src/Blocks/BlockBed.cpp
Expand Up @@ -5,7 +5,6 @@


#include "BroadcastInterface.h"
#include "ChunkInterface.h"
#include "Entities/../World.h"
#include "Entities/Player.h"
#include "WorldInterface.h"
Expand Down Expand Up @@ -64,21 +63,22 @@ class cPlayerBedStateUnsetter :
public cPlayerListCallback
{
public:
cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) :
m_Position(a_Position), m_WorldInterface(a_WorldInterface)
cPlayerBedStateUnsetter(Vector3i a_Position, cChunkInterface & a_ChunkInterface) :
m_Position(a_Position),
m_ChunkInterface(a_ChunkInterface)
{
}

virtual bool Item(cPlayer * a_Player) override
{
cBlockBedHandler::SetBedOccupationState(m_ChunkInterface, a_Player->GetLastBedPos(), false);
a_Player->SetIsInBed(false);
m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2);
return false;
}

private:
Vector3i m_Position;
cWorldInterface & m_WorldInterface;
cChunkInterface & m_ChunkInterface;
};


Expand All @@ -97,15 +97,15 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
if (a_WorldInterface.GetTimeOfDay() > 13000)
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (Meta & 0x4)
if ((Meta & 0x4) == 0x4)
{
a_Player->SendMessageFailure("This bed is occupied");
}
else
{
Vector3i PillowDirection(0, 0, 0);

if (Meta & 0x8)
if ((Meta & 0x8) == 0x8)
{
// Is pillow
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX, a_BlockY, a_BlockZ);
Expand All @@ -122,19 +122,12 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
}
}

a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit
a_Player->SetIsInBed(true);
a_Player->SetBedPos(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
SetBedOccupationState(a_ChunkInterface, a_Player->GetLastBedPos(), true);
a_Player->SetIsInBed(true);
a_Player->SendMessageSuccess("Home position set successfully");

cTimeFastForwardTester Tester;
if (a_WorldInterface.ForEachPlayer(Tester))
{
cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface);
a_WorldInterface.ForEachPlayer(Unsetter);
a_WorldInterface.SetTimeOfDay(0);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
}
a_WorldInterface.ScheduleTask(20, cWorld::cTaskTryAwakeSleepingPlayers(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_ChunkInterface));
}
}
else
Expand Down
25 changes: 17 additions & 8 deletions src/Blocks/BlockBed.h
Expand Up @@ -4,9 +4,9 @@
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Item.h"
#include "ChunkInterface.h"


class cChunkInterface;
class cPlayer;
class cWorldInterface;

Expand All @@ -21,32 +21,27 @@ class cBlockBedHandler :
: cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}



virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;


virtual bool IsUseable(void) override
{
return true;
}


virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(E_ITEM_BED, 1, 0));
}


virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override
{
return true;
}



// Bed specific helper functions
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
Expand All @@ -61,7 +56,6 @@ class cBlockBedHandler :
return ((char)a_Rotation + 2) % 4;
}


static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch (a_MetaData)
Expand All @@ -73,6 +67,21 @@ class cBlockBedHandler :
}
return Vector3i();
}

static void SetBedOccupationState(cChunkInterface & a_ChunkInterface, const Vector3i & a_BedPosition, bool a_IsOccupied)
{
auto Meta = a_ChunkInterface.GetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z);
if (a_IsOccupied)
{
Meta |= 0x04; // Where 0x4 = occupied bit
}
else
{
Meta &= 0x0b; // Clear the "occupied" bit of the bed's block
}

a_ChunkInterface.SetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z, Meta);
}
} ;


Expand Down
5 changes: 5 additions & 0 deletions src/Blocks/WorldInterface.h
Expand Up @@ -11,6 +11,7 @@ typedef cItemCallback<cBlockEntity> cBlockEntityCallback;

class cMonster;
class cPlayer;
class cTask;


class cWorldInterface
Expand Down Expand Up @@ -59,4 +60,8 @@ class cWorldInterface
/** Wakes up the simulators for the specified block */
virtual void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) = 0;

/** Queues a task onto the tick thread, with the specified delay.
The task object will be deleted once the task is finished */
virtual void ScheduleTask(int a_DelayTicks, cTask * a_Task) = 0;

};
5 changes: 1 addition & 4 deletions src/ChunkMap.cpp
Expand Up @@ -1322,10 +1322,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP
void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
cChunkInterface ChunkInterface(this);
if (a_BlockType == E_BLOCK_AIR)
{
BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ);
}
BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ);

int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ);
Expand Down
28 changes: 3 additions & 25 deletions src/ClientHandle.cpp
Expand Up @@ -18,6 +18,7 @@
#include "Items/ItemHandler.h"
#include "Blocks/BlockHandler.h"
#include "Blocks/BlockSlab.h"
#include "Blocks/BlockBed.h"
#include "Blocks/ChunkInterface.h"

#include "Root.h"
Expand Down Expand Up @@ -1498,30 +1499,6 @@ void cClientHandle::HandleAnimation(int a_Animation)
return;
}

// Because the animation ID sent to servers by clients are different to those sent back, we need this
switch (a_Animation)
{
case 0: // No animation - wiki.vg doesn't say that client has something specific for it, so I suppose it will just become -1
case 1:
case 2:
case 3:
{
a_Animation--; // Offset by -1
break;
}
case 5:
case 6:
case 7:
{
a_Animation -= 2; // Offset by -2
break;
}
default: // Anything else is the same
{
break;
}
}

m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, a_Animation, this);
}

Expand Down Expand Up @@ -1763,7 +1740,8 @@ void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
return;
}

m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
cBlockBedHandler::SetBedOccupationState(cChunkInterface(GetPlayer()->GetWorld()->GetChunkMap()), GetPlayer()->GetLastBedPos(), false);
GetPlayer()->SetIsInBed(false);
}


Expand Down
14 changes: 12 additions & 2 deletions src/Entities/Player.h
Expand Up @@ -314,8 +314,18 @@ class cPlayer :

// tolua_end

/** Sets a player's in-bed state; we can't be sure plugins will keep this value updated, so no exporting */
void SetIsInBed(bool a_Flag) { m_bIsInBed = a_Flag; }
/** 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);
}
}

/** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
void StartEating(void);
Expand Down
4 changes: 1 addition & 3 deletions src/Protocol/Protocol18x.cpp
Expand Up @@ -2101,9 +2101,7 @@ void cProtocol180::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)

void cProtocol180::HandlePacketAnimation(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadBEInt, int, EntityID);
HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Animation);
m_Client->HandleAnimation(Animation);
m_Client->HandleAnimation(1); // Packet exists solely for arm-swing notification
}


Expand Down
27 changes: 26 additions & 1 deletion src/World.cpp
Expand Up @@ -47,6 +47,7 @@
#include "Generating/Trees.h"
#include "Bindings/PluginManager.h"
#include "Blocks/BlockHandler.h"
#include "Blocks/BlockBed.cpp"

#include "Tracer.h"

Expand Down Expand Up @@ -3578,7 +3579,7 @@ void cWorld::cTaskUnloadUnusedChunks::Run(cWorld & a_World)


////////////////////////////////////////////////////////////////////////////////
// cWorld::cTaskSendBlockTo
// cWorld::cTaskSendBlockToAllPlayers

cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue) :
m_SendQueue(a_SendQueue)
Expand Down Expand Up @@ -3620,6 +3621,30 @@ void cWorld::cTaskSendBlockToAllPlayers::Run(cWorld & a_World)



////////////////////////////////////////////////////////////////////////////////
// cWorld::cTaskSendBlockToAllPlayers

cWorld::cTaskTryAwakeSleepingPlayers::cTaskTryAwakeSleepingPlayers(const Vector3i & a_Position, cChunkInterface & a_ChunkInterface) :
m_Position(a_Position),
m_ChunkInterface(a_ChunkInterface)
{
}

void cWorld::cTaskTryAwakeSleepingPlayers::Run(cWorld & a_World)
{
cTimeFastForwardTester Tester;
if (a_World.ForEachPlayer(Tester))
{
cPlayerBedStateUnsetter Unsetter(m_Position, m_ChunkInterface);
a_World.ForEachPlayer(Unsetter);
a_World.SetTimeOfDay(0);
}
}





////////////////////////////////////////////////////////////////////////////////
// cWorld::cChunkGeneratorCallbacks:

Expand Down
18 changes: 17 additions & 1 deletion src/World.h
Expand Up @@ -45,6 +45,7 @@ class cEntity;
class cBlockEntity;
class cWorldGenerator; // The generator that actually generates the chunks for a single world
class cChunkGenerator; // The thread responsible for generating chunks
class cChunkInterface;
class cBeaconEntity;
class cChestEntity;
class cDispenserEntity;
Expand Down Expand Up @@ -140,6 +141,21 @@ class cWorld :
std::vector<Vector3i> m_SendQueue;
};

class cTaskTryAwakeSleepingPlayers :
public cTask
{
public:
cTaskTryAwakeSleepingPlayers(const Vector3i & a_Position, cChunkInterface & a_ChunkInterface);

protected:
// cTask overrides:
virtual void Run(cWorld & a_World) override;

private:
Vector3i m_Position;
cChunkInterface & m_ChunkInterface;
};


static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
{
Expand Down Expand Up @@ -695,7 +711,7 @@ class cWorld :

/** Queues a task onto the tick thread, with the specified delay.
The task object will be deleted once the task is finished */
void ScheduleTask(int a_DelayTicks, cTask * a_Task);
virtual void ScheduleTask(int a_DelayTicks, cTask * a_Task) override;

/** Returns the number of chunks loaded */
int GetNumChunks() const; // tolua_export
Expand Down

0 comments on commit 3869f76

Please sign in to comment.