Cuberite
A lightweight, fast and extensible game server for Minecraft
ChestEntity.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "ChestEntity.h"
5 #include "../Chunk.h"
6 #include "../BlockInfo.h"
7 #include "../Item.h"
8 #include "../Entities/Player.h"
9 #include "../UI/ChestWindow.h"
10 #include "../ClientHandle.h"
11 #include "../Mobs/Ocelot.h"
12 
13 
14 
15 
16 
17 cChestEntity::cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
18  Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World),
19  m_NumActivePlayers(0),
20  m_Neighbour(nullptr)
21 {
22 }
23 
24 
25 
26 
27 
29 {
30  if (m_Neighbour == nullptr)
31  {
32  return *this;
33  }
34 
35  // The primary chest should be the one with lesser X or Z coord:
36  return (
37  (m_Neighbour->GetPosX() < GetPosX()) ||
38  (m_Neighbour->GetPosZ() < GetPosZ())
39  ) ? *m_Neighbour : *this;
40 }
41 
42 
43 
44 
45 
47 {
48  // If we're the primary, then our neighbour is the secondary, and vice versa:
49  return (&GetPrimaryChest() == this) ? m_Neighbour : this;
50 }
51 
52 
53 
54 
55 
56 bool cChestEntity::ScanNeighbour(cChunk & a_Chunk, Vector3i a_Position)
57 {
58  const auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_Position);
59 
60  if ((Chunk == nullptr) || !Chunk->IsValid())
61  {
62  // If a chest was in fact there, they'll find us when their chunk loads.
63  return false;
64  }
65 
66  const auto BlockEntity = Chunk->GetBlockEntityRel(a_Position);
67 
68  if ((BlockEntity == nullptr) || (BlockEntity->GetBlockType() != m_BlockType))
69  {
70  // Neighbouring block is not the same type of chest:
71  return false;
72  }
73 
74  m_Neighbour = static_cast<cChestEntity *>(BlockEntity);
75  return true;
76 }
77 
78 
79 
80 
81 
83 {
84  const auto Window = GetWindow();
85  if (Window != nullptr)
86  {
87  Window->OwnerDestroyed();
88  }
89 }
90 
91 
92 
93 
94 
96 {
97  return (
98  (GetPosY() < cChunkDef::Height - 1) &&
99  (
102  )
103  );
104 }
105 
106 
107 
108 
109 
111 {
112  if (m_Neighbour != nullptr)
113  {
114  ASSERT(&GetPrimaryChest() == this); // Should only open windows for the primary chest.
115 
116  OpenWindow(new cChestWindow(this, m_Neighbour));
117  }
118  else
119  {
120  // There is no chest neighbour, open a single-chest window:
121  OpenWindow(new cChestWindow(this));
122  }
123 }
124 
125 
126 
127 
128 
130 {
131  Super::CopyFrom(a_Src);
132  auto & src = static_cast<const cChestEntity &>(a_Src);
133  m_Contents.CopyFrom(src.m_Contents);
134 
135  // Reset the neighbor and player count, there's no sense in copying these:
136  m_Neighbour = nullptr;
137  m_NumActivePlayers = 0;
138 }
139 
140 
141 
142 
143 
144 void cChestEntity::OnAddToWorld(cWorld & a_World, cChunk & a_Chunk)
145 {
146  Super::OnAddToWorld(a_World, a_Chunk);
147 
148  // Scan horizontally adjacent blocks for any neighbouring chest of the same type:
149  if (
150  const auto Position = GetRelPos();
151 
152  ScanNeighbour(a_Chunk, Position.addedX(-1)) ||
153  ScanNeighbour(a_Chunk, Position.addedX(+1)) ||
154  ScanNeighbour(a_Chunk, Position.addedZ(-1)) ||
155  ScanNeighbour(a_Chunk, Position.addedZ(+1))
156  )
157  {
158  m_Neighbour->m_Neighbour = this;
159  m_Neighbour->DestroyWindow(); // Force neighbour's window shut. Does Mojang server do this or should a double window open?
160  }
161 }
162 
163 
164 
165 
166 
168 {
169  if (m_Neighbour != nullptr)
170  {
171  // Neighbour may share a window with us, force the window shut:
173  m_Neighbour->m_Neighbour = nullptr;
174  }
175 
176  DestroyWindow();
177 }
178 
179 
180 
181 
182 
184 {
185  a_Client.SendUpdateBlockEntity(*this);
186 }
187 
188 
189 
190 
191 
193 {
194  if (IsBlocked())
195  {
196  // Obstruction, don't open
197  return true;
198  }
199 
200  if ((m_Neighbour != nullptr) && m_Neighbour->IsBlocked())
201  {
202  return true;
203  }
204 
205  if (m_BlockType == E_BLOCK_CHEST)
206  {
208  }
209  else // E_BLOCK_TRAPPED_CHEST
210  {
212  }
213 
214  auto & PrimaryChest = GetPrimaryChest();
215  cWindow * Window = PrimaryChest.GetWindow();
216 
217  // If the window is not created, open it anew:
218  if (Window == nullptr)
219  {
220  PrimaryChest.OpenNewWindow();
221  Window = PrimaryChest.GetWindow();
222  }
223 
224  // Open the window for the player:
225  if (Window != nullptr)
226  {
227  if (a_Player->GetWindow() != Window)
228  {
229  a_Player->OpenWindow(*Window);
230  }
231  }
232 
233  return true;
234 }
235 
236 
237 
238 
239 
240 void cChestEntity::OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum)
241 {
242  ASSERT(a_Grid == &m_Contents);
243 
244  // Have cBlockEntityWithItems update redstone and try to broadcast our window:
245  Super::OnSlotChanged(a_Grid, a_SlotNum);
246 
247  cWindow * Window = GetWindow();
248  if ((Window == nullptr) && (m_Neighbour != nullptr))
249  {
250  // Window was null, Super will have failed.
251  // Neighbour might own the window:
252  Window = m_Neighbour->GetWindow();
253  }
254 
255  if (Window != nullptr)
256  {
257  Window->BroadcastWholeWindow();
258  }
259 }
static int GetBlock(lua_State *a_LuaState)
Templated bindings for the GetBlock___() functions.
@ E_BLOCK_CHEST
Definition: BlockType.h:64
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
#define ASSERT(x)
Definition: Globals.h:276
Vector3< double > Vector3d
Definition: Vector3.h:485
BLOCKTYPE m_BlockType
The blocktype representing this particular instance in the world.
Definition: BlockEntity.h:120
cWorld * GetWorld() const
Definition: BlockEntity.h:99
int GetPosZ() const
Definition: BlockEntity.h:93
Vector3i GetPos() const
Definition: BlockEntity.h:90
int GetPosY() const
Definition: BlockEntity.h:92
int GetPosX() const
Definition: BlockEntity.h:91
Vector3i GetRelPos() const
Definition: BlockEntity.h:95
virtual void OnAddToWorld(cWorld &a_World, cChunk &a_Chunk)
Called when the block entity object is added to a world.
virtual void CopyFrom(const cBlockEntity &a_Src) override
Copies all properties of a_Src into this entity, except for its m_World and location.
virtual void OnSlotChanged(cItemGrid *a_Grid, int a_SlotNum) override
Called whenever a slot changes.
virtual void OnAddToWorld(cWorld &a_World, cChunk &a_Chunk) override
Called when the block entity object is added to a world.
cChestEntity * GetSecondaryChest()
Returns the associated secondary chest, if any.
Definition: ChestEntity.cpp:46
cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld *a_World)
Definition: ChestEntity.cpp:17
bool ScanNeighbour(cChunk &a_Chunk, Vector3i a_Position)
Search the given horizontally adjacent relative position for a neighbouring chest of the same type.
Definition: ChestEntity.cpp:56
void OpenNewWindow()
Opens a new chest window where this is the primary chest and any neighbour is the secondary.
cChestEntity * m_Neighbour
Neighbouring chest that links to form a double chest.
Definition: ChestEntity.h:61
virtual void CopyFrom(const cBlockEntity &a_Src) override
Copies all properties of a_Src into this entity, except for its m_World and location.
cChestEntity & GetPrimaryChest()
Returns the associated primary chest.
Definition: ChestEntity.cpp:28
virtual bool UsedBy(cPlayer *a_Player) override
Called when a player uses this entity; should open the UI window.
bool IsBlocked()
Returns true if the chest should not be accessible by players.
Definition: ChestEntity.cpp:95
virtual void OnSlotChanged(cItemGrid *a_Grid, int a_SlotNum) override
cItemGrid::cListener overrides:
int m_NumActivePlayers
Number of players who currently have this chest open.
Definition: ChestEntity.h:58
virtual void SendTo(cClientHandle &a_Client) override
Sends the packet defining the block entity to the client specified.
void DestroyWindow()
Forces any players to close the owned window.
Definition: ChestEntity.cpp:82
virtual void OnRemoveFromWorld() override
Called when the block entity object is removed from a world.
static bool IsTransparent(BLOCKTYPE Block)
Is a block transparent? (https://minecraft.wiki/w/Opacity)
Definition: BlockInfo.cpp:961
Definition: Chunk.h:36
cChunk * GetRelNeighborChunkAdjustCoords(Vector3i &a_RelPos) const
Returns the chunk into which the relatively-specified block belongs.
Definition: Chunk.cpp:1885
cBlockEntity * GetBlockEntityRel(Vector3i a_RelPos)
Returns the block entity at the specified (relative) coords.
Definition: Chunk.cpp:1436
static const int Height
Definition: ChunkDef.h:125
void SendUpdateBlockEntity(cBlockEntity &a_BlockEntity)
Definition: Player.h:29
StatisticsManager & GetStatistics()
Return the associated statistic and achievement manager.
Definition: Player.h:237
void OpenWindow(cWindow &a_Window)
Opens the specified window; closes the current one first using CloseWindow()
Definition: Player.cpp:1123
cWindow * GetWindow(void)
Definition: Player.h:262
void CopyFrom(const cItemGrid &a_Src)
Copies all items from a_Src to this grid.
Definition: ItemGrid.cpp:83
static bool IsCatSittingOnBlock(cWorld *a_World, Vector3d a_BlockPosition)
Returns true if there's a cat sitting above the given position.
Definition: Ocelot.cpp:196
std::unordered_map< CustomStatistic, StatValue > Custom
Represents a UI window.
Definition: Window.h:54
void BroadcastWholeWindow(void)
Sends the contents of the whole window to all clients of this window.
Definition: Window.cpp:393
cWindow * GetWindow(void) const
Definition: WindowOwner.h:40
void OpenWindow(cWindow *a_Window)
Definition: WindowOwner.h:34
Definition: World.h:53