1
0
Fork 0

Double chest window fix (#3735)

This commit is contained in:
peterbell10 2017-05-28 19:07:38 +01:00 committed by Lukas Pioch
parent de0c86a690
commit f261a03c14
2 changed files with 131 additions and 53 deletions

View File

@ -13,21 +13,33 @@
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type) : cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type) :
super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_NumActivePlayers(0) m_NumActivePlayers(0),
m_Neighbour(nullptr)
{ {
int ChunkX = 0, ChunkZ = 0;
cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ);
if (
(m_World != nullptr) &&
m_World->IsChunkValid(ChunkX, ChunkZ)
)
{
ScanNeighbours();
}
} }
cChestEntity::~cChestEntity() cChestEntity::~cChestEntity()
{ {
cWindow * Window = GetWindow(); if (m_Neighbour != nullptr)
if (Window != nullptr)
{ {
Window->OwnerDestroyed(); // Neighbour may share a window with us, force the window shut
m_Neighbour->DestroyWindow();
m_Neighbour->m_Neighbour = nullptr;
} }
DestroyWindow();
} }
@ -46,12 +58,42 @@ void cChestEntity::SendTo(cClientHandle & a_Client)
bool cChestEntity::UsedBy(cPlayer * a_Player) bool cChestEntity::UsedBy(cPlayer * a_Player)
{ {
if (IsBlocked())
{
// Obstruction, don't open
return true;
}
if (m_Neighbour == nullptr)
{
ScanNeighbours();
}
// The primary chest should be the one with lesser X or Z coord:
cChestEntity * PrimaryChest = this;
if (m_Neighbour != nullptr)
{
if (m_Neighbour->IsBlocked())
{
// Obstruction, don't open
return true;
}
if (
(m_Neighbour->GetPosX() > GetPosX()) ||
(m_Neighbour->GetPosZ() > GetPosZ())
)
{
PrimaryChest = m_Neighbour;
}
}
// If the window is not created, open it anew: // If the window is not created, open it anew:
cWindow * Window = GetWindow(); cWindow * Window = PrimaryChest->GetWindow();
if (Window == nullptr) if (Window == nullptr)
{ {
OpenNewWindow(); PrimaryChest->OpenNewWindow();
Window = GetWindow(); Window = PrimaryChest->GetWindow();
} }
// Open the window for the player: // Open the window for the player:
@ -77,62 +119,87 @@ bool cChestEntity::UsedBy(cPlayer * a_Player)
void cChestEntity::OpenNewWindow(void) void cChestEntity::ScanNeighbours()
{ {
// TODO: cats are an obstruction // Callback for finding neighbouring chest:
if ((GetPosY() < cChunkDef::Height - 1) && !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()))) class cFindNeighbour :
{
// Obstruction, don't open
return;
}
// Callback for opening together with neighbor chest:
class cOpenDouble :
public cChestCallback public cChestCallback
{ {
cChestEntity * m_ThisChest;
public: public:
cOpenDouble(cChestEntity * a_ThisChest) : cChestEntity * m_Neighbour;
m_ThisChest(a_ThisChest)
cFindNeighbour() :
m_Neighbour(nullptr)
{ {
} }
virtual bool Item(cChestEntity * a_Chest) override virtual bool Item(cChestEntity * a_Chest) override
{ {
if ((a_Chest->GetPosY() < cChunkDef::Height - 1) && !cBlockInfo::IsTransparent(a_Chest->GetWorld()->GetBlock(a_Chest->GetPosX(), a_Chest->GetPosY() + 1, a_Chest->GetPosZ()))) m_Neighbour = a_Chest;
{
// Obstruction, don't open
return false;
}
// The primary chest should eb the one with lesser X or Z coord:
cChestEntity * Primary = a_Chest;
cChestEntity * Secondary = m_ThisChest;
if (
(Primary->GetPosX() > Secondary->GetPosX()) ||
(Primary->GetPosZ() > Secondary->GetPosZ())
)
{
std::swap(Primary, Secondary);
}
m_ThisChest->OpenWindow(new cChestWindow(Primary, Secondary));
return false; return false;
} }
} ; };
// Scan neighbors for adjacent chests: // Scan horizontally adjacent blocks for any neighbouring chest:
cOpenDouble OpenDbl(this); cFindNeighbour FindNeighbour;
if ( if (
m_World->DoWithChestAt(m_PosX - 1, m_PosY, m_PosZ, OpenDbl) || m_World->DoWithChestAt(m_PosX - 1, m_PosY, m_PosZ, FindNeighbour) ||
m_World->DoWithChestAt(m_PosX + 1, m_PosY, m_PosZ, OpenDbl) || m_World->DoWithChestAt(m_PosX + 1, m_PosY, m_PosZ, FindNeighbour) ||
m_World->DoWithChestAt(m_PosX, m_PosY, m_PosZ - 1, OpenDbl) || m_World->DoWithChestAt(m_PosX, m_PosY, m_PosZ - 1, FindNeighbour) ||
m_World->DoWithChestAt(m_PosX, m_PosY, m_PosZ + 1, OpenDbl) m_World->DoWithChestAt(m_PosX, m_PosY, m_PosZ + 1, FindNeighbour)
) )
{ {
// The double-chest window has been opened in the callback m_Neighbour = FindNeighbour.m_Neighbour;
return; m_Neighbour->m_Neighbour = this;
// Force neighbour's window shut. Does Mojang server do this or should a double window open?
m_Neighbour->DestroyWindow();
} }
}
// There is no chest neighbor, open a single-chest window:
OpenWindow(new cChestWindow(this));
void cChestEntity::OpenNewWindow(void)
{
if (m_Neighbour != nullptr)
{
ASSERT( // This should be the primary chest
(m_Neighbour->GetPosX() < GetPosX()) ||
(m_Neighbour->GetPosZ() < GetPosZ())
);
OpenWindow(new cChestWindow(this, m_Neighbour));
}
else
{
// There is no chest neighbour, open a single-chest window:
OpenWindow(new cChestWindow(this));
}
}
void cChestEntity::DestroyWindow()
{
cWindow * Window = GetWindow();
if (Window != nullptr)
{
Window->OwnerDestroyed();
CloseWindow();
}
}
bool cChestEntity::IsBlocked()
{
// TODO: cats are an obstruction
return (
(GetPosY() >= cChunkDef::Height - 1) ||
!cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()))
);
} }

View File

@ -39,9 +39,17 @@ public:
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual bool UsedBy(cPlayer * a_Player) override; virtual bool UsedBy(cPlayer * a_Player) override;
/** Opens a new chest window for this chest. /** Search horizontally adjacent blocks for neighbouring chests and links them together. */
Scans for neighbors to open a double chest window, if appropriate. */ void ScanNeighbours();
void OpenNewWindow(void);
/** Opens a new chest window where this is the primary chest and any neighbour is the secondary. */
void OpenNewWindow();
/** Forces any players to close the owned window. */
void DestroyWindow();
/** Returns true if the chest should not be accessible by players. */
bool IsBlocked();
/** Gets the number of players who currently have this chest open */ /** Gets the number of players who currently have this chest open */
int GetNumberOfPlayers(void) const { return m_NumActivePlayers; } int GetNumberOfPlayers(void) const { return m_NumActivePlayers; }
@ -54,6 +62,9 @@ private:
/** Number of players who currently have this chest open */ /** Number of players who currently have this chest open */
int m_NumActivePlayers; int m_NumActivePlayers;
/** Neighbouring chest that links to form a double chest */
cChestEntity * m_Neighbour;
/** cItemGrid::cListener overrides: */ /** cItemGrid::cListener overrides: */
virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override
{ {