1
0

Handle client 'leave bed' request

* Fixes #1728
This commit is contained in:
Tiger Wang 2015-02-08 21:21:48 +00:00
parent 1ce9164694
commit 3869f76cc2
9 changed files with 92 additions and 61 deletions

View File

@ -5,7 +5,6 @@
#include "BroadcastInterface.h" #include "BroadcastInterface.h"
#include "ChunkInterface.h"
#include "Entities/../World.h" #include "Entities/../World.h"
#include "Entities/Player.h" #include "Entities/Player.h"
#include "WorldInterface.h" #include "WorldInterface.h"
@ -64,21 +63,22 @@ class cPlayerBedStateUnsetter :
public cPlayerListCallback public cPlayerListCallback
{ {
public: public:
cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) : cPlayerBedStateUnsetter(Vector3i a_Position, cChunkInterface & a_ChunkInterface) :
m_Position(a_Position), m_WorldInterface(a_WorldInterface) m_Position(a_Position),
m_ChunkInterface(a_ChunkInterface)
{ {
} }
virtual bool Item(cPlayer * a_Player) override virtual bool Item(cPlayer * a_Player) override
{ {
cBlockBedHandler::SetBedOccupationState(m_ChunkInterface, a_Player->GetLastBedPos(), false);
a_Player->SetIsInBed(false); a_Player->SetIsInBed(false);
m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2);
return false; return false;
} }
private: private:
Vector3i m_Position; Vector3i m_Position;
cWorldInterface & m_WorldInterface; cChunkInterface & m_ChunkInterface;
}; };
@ -97,7 +97,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
if (a_WorldInterface.GetTimeOfDay() > 13000) if (a_WorldInterface.GetTimeOfDay() > 13000)
{ {
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); 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"); a_Player->SendMessageFailure("This bed is occupied");
} }
@ -105,7 +105,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
{ {
Vector3i PillowDirection(0, 0, 0); Vector3i PillowDirection(0, 0, 0);
if (Meta & 0x8) if ((Meta & 0x8) == 0x8)
{ {
// Is pillow // Is pillow
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX, a_BlockY, a_BlockZ); a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX, a_BlockY, a_BlockZ);
@ -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)); 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"); a_Player->SendMessageSuccess("Home position set successfully");
cTimeFastForwardTester Tester; a_WorldInterface.ScheduleTask(20, cWorld::cTaskTryAwakeSleepingPlayers(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_ChunkInterface));
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
}
} }
} }
else else

View File

@ -4,9 +4,9 @@
#include "BlockHandler.h" #include "BlockHandler.h"
#include "MetaRotator.h" #include "MetaRotator.h"
#include "Item.h" #include "Item.h"
#include "ChunkInterface.h"
class cChunkInterface;
class cPlayer; class cPlayer;
class cWorldInterface; class cWorldInterface;
@ -21,17 +21,14 @@ public:
: cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType) : 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 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 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 virtual bool IsUseable(void) override
{ {
return true; return true;
} }
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
@ -39,14 +36,12 @@ public:
a_Pickups.push_back(cItem(E_ITEM_BED, 1, 0)); a_Pickups.push_back(cItem(E_ITEM_BED, 1, 0));
} }
virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override
{ {
return true; return true;
} }
// Bed specific helper functions // Bed specific helper functions
static NIBBLETYPE RotationToMetaData(double a_Rotation) static NIBBLETYPE RotationToMetaData(double a_Rotation)
{ {
@ -61,7 +56,6 @@ public:
return ((char)a_Rotation + 2) % 4; return ((char)a_Rotation + 2) % 4;
} }
static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData) static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData)
{ {
switch (a_MetaData) switch (a_MetaData)
@ -73,6 +67,21 @@ public:
} }
return Vector3i(); 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);
}
} ; } ;

View File

@ -11,6 +11,7 @@ typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
class cMonster; class cMonster;
class cPlayer; class cPlayer;
class cTask;
class cWorldInterface class cWorldInterface
@ -59,4 +60,8 @@ public:
/** Wakes up the simulators for the specified block */ /** Wakes up the simulators for the specified block */
virtual void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) = 0; 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;
}; };

View File

@ -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) void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{ {
cChunkInterface ChunkInterface(this); 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; int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ);

View File

@ -18,6 +18,7 @@
#include "Items/ItemHandler.h" #include "Items/ItemHandler.h"
#include "Blocks/BlockHandler.h" #include "Blocks/BlockHandler.h"
#include "Blocks/BlockSlab.h" #include "Blocks/BlockSlab.h"
#include "Blocks/BlockBed.h"
#include "Blocks/ChunkInterface.h" #include "Blocks/ChunkInterface.h"
#include "Root.h" #include "Root.h"
@ -1498,30 +1499,6 @@ void cClientHandle::HandleAnimation(int a_Animation)
return; 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); m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, a_Animation, this);
} }
@ -1763,7 +1740,8 @@ void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
return; return;
} }
m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2); cBlockBedHandler::SetBedOccupationState(cChunkInterface(GetPlayer()->GetWorld()->GetChunkMap()), GetPlayer()->GetLastBedPos(), false);
GetPlayer()->SetIsInBed(false);
} }

View File

@ -314,8 +314,18 @@ public:
// tolua_end // tolua_end
/** Sets a player's in-bed state; we can't be sure plugins will keep this value updated, so no exporting */ /** Sets a player's in-bed state
void SetIsInBed(bool a_Flag) { m_bIsInBed = a_Flag; } 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 */ /** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
void StartEating(void); void StartEating(void);

View File

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

View File

@ -47,6 +47,7 @@
#include "Generating/Trees.h" #include "Generating/Trees.h"
#include "Bindings/PluginManager.h" #include "Bindings/PluginManager.h"
#include "Blocks/BlockHandler.h" #include "Blocks/BlockHandler.h"
#include "Blocks/BlockBed.cpp"
#include "Tracer.h" #include "Tracer.h"
@ -3578,7 +3579,7 @@ void cWorld::cTaskUnloadUnusedChunks::Run(cWorld & a_World)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cWorld::cTaskSendBlockTo // cWorld::cTaskSendBlockToAllPlayers
cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue) : cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue) :
m_SendQueue(a_SendQueue) m_SendQueue(a_SendQueue)
@ -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: // cWorld::cChunkGeneratorCallbacks:

View File

@ -45,6 +45,7 @@ class cEntity;
class cBlockEntity; class cBlockEntity;
class cWorldGenerator; // The generator that actually generates the chunks for a single world class cWorldGenerator; // The generator that actually generates the chunks for a single world
class cChunkGenerator; // The thread responsible for generating chunks class cChunkGenerator; // The thread responsible for generating chunks
class cChunkInterface;
class cBeaconEntity; class cBeaconEntity;
class cChestEntity; class cChestEntity;
class cDispenserEntity; class cDispenserEntity;
@ -140,6 +141,21 @@ public:
std::vector<Vector3i> m_SendQueue; 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 static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
{ {
@ -695,7 +711,7 @@ public:
/** Queues a task onto the tick thread, with the specified delay. /** Queues a task onto the tick thread, with the specified delay.
The task object will be deleted once the task is finished */ 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 */ /** Returns the number of chunks loaded */
int GetNumChunks() const; // tolua_export int GetNumChunks() const; // tolua_export