Cuberite
A lightweight, fast and extensible game server for Minecraft
FurnaceEntity.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 "FurnaceEntity.h"
5 #include "../UI/FurnaceWindow.h"
6 #include "../Entities/Player.h"
7 #include "../Root.h"
8 #include "../Chunk.h"
9 
10 
11 
12 
13 
14 enum
15 {
19 } ;
20 
21 
22 
23 
24 
25 cFurnaceEntity::cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
26  Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World),
27  m_CurrentRecipe(nullptr),
28  m_IsCooking(a_BlockType == E_BLOCK_LIT_FURNACE),
29  m_NeedCookTime(0),
30  m_TimeCooked(0),
31  m_FuelBurnTime(0),
32  m_TimeBurned(0),
33  m_RewardCounter(0),
34  m_IsLoading(false)
35 {
36  m_Contents.AddListener(*this);
37 }
38 
39 
40 
41 
42 
44 {
45  Super::CopyFrom(a_Src);
46  auto & src = static_cast<const cFurnaceEntity &>(a_Src);
47  m_Contents.CopyFrom(src.m_Contents);
48  m_CurrentRecipe = src.m_CurrentRecipe;
49  m_FuelBurnTime = src.m_FuelBurnTime;
50  m_IsCooking = src.m_IsCooking;
51  m_IsLoading = src.m_IsLoading;
52  m_LastInput = src.m_LastInput;
53  m_NeedCookTime = src.m_NeedCookTime;
54  m_TimeBurned = src.m_TimeBurned;
55  m_TimeCooked = src.m_TimeCooked;
56 }
57 
58 
59 
60 
61 
63 {
64  const auto Window = GetWindow();
65  if (Window != nullptr)
66  {
67  // Tell window its owner is destroyed:
68  Window->OwnerDestroyed();
69  }
70 }
71 
72 
73 
74 
75 
77 {
78  // Nothing needs to be sent
79  UNUSED(a_Client);
80 }
81 
82 
83 
84 
85 
86 bool cFurnaceEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
87 {
88  UNUSED(a_Dt);
89 
90  if (m_FuelBurnTime <= 0)
91  {
92  // If a furnace is out of fuel, the progress bar reverses at twice the speed of cooking.
93  m_TimeCooked = std::max((m_TimeCooked - 2), 0);
94 
95  // Reset progressbars, block type, and bail out
99  return false;
100  }
101 
102  if (m_IsCooking)
103  {
104  m_TimeCooked++;
106  {
107  // Finished smelting one item
108  FinishOne();
109  }
110  }
111 
112  m_TimeBurned++;
114  {
115  // The current fuel has been exhausted, use another one, if possible
116  BurnNewFuel();
117  }
118 
120 
121  return true;
122 }
123 
124 
125 
126 
127 
129 {
131 
132  cWindow * Window = GetWindow();
133  if (Window == nullptr)
134  {
135  OpenWindow(new cFurnaceWindow(this));
136  Window = GetWindow();
137  }
138 
139  if (Window != nullptr)
140  {
141  if (a_Player->GetWindow() != Window)
142  {
143  a_Player->OpenWindow(*Window);
144  }
145  }
146 
147  UpdateProgressBars(true);
148  return true;
149 }
150 
151 
152 
153 
154 
156 {
157  UpdateInput();
158  UpdateFuel();
159  return m_IsCooking;
160 }
161 
162 
163 
164 
165 
167 {
168  int Reward = FloorC(m_RewardCounter);
169  float Remainder = m_RewardCounter - static_cast<float>(Reward);
170  // Remainder is used as the percent chance of getting an extra xp point
171  if (GetRandomProvider().RandBool(Remainder))
172  {
173  Reward++;
174  }
175  m_RewardCounter = 0.0;
176  return Reward;
177 }
178 
179 
180 
181 
182 
183 void cFurnaceEntity::BroadcastProgress(size_t a_ProgressbarID, short a_Value)
184 {
185  cWindow * Window = GetWindow();
186  if (Window != nullptr)
187  {
188  Window->SetProperty(a_ProgressbarID, a_Value);
189  }
190 }
191 
192 
193 
194 
195 
197 {
198  m_TimeCooked = 0;
200 
202  {
204  }
205  else
206  {
208  }
210 }
211 
212 
213 
214 
215 
217 {
219  int NewTime = FR->GetBurnTime(m_Contents.GetSlot(fsFuel));
220  if ((NewTime == 0) || !CanCookInputToOutput())
221  {
222  // The item in the fuel slot is not suitable
223  // or the input and output isn't available for cooking
224  SetBurnTimes(0, 0);
225  SetIsCooking(false);
226  return;
227  }
228 
229  // Burn one new fuel:
230  SetBurnTimes(NewTime, 0);
231  SetIsCooking(true);
233  {
235  }
236  else
237  {
239  }
240 }
241 
242 
243 
244 
245 
246 void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
247 {
248  Super::OnSlotChanged(a_ItemGrid, a_SlotNum);
249 
250  if (m_IsLoading)
251  {
252  return;
253  }
254 
255  ASSERT(a_ItemGrid == &m_Contents);
256  switch (a_SlotNum)
257  {
258  case fsInput: UpdateInput(); break;
259  case fsFuel: UpdateFuel(); break;
260  case fsOutput: UpdateOutput(); break;
261  default: ASSERT(!"Invalid furnace slot update!"); break;
262  }
263 }
264 
265 
266 
267 
268 
270 {
272  {
273  // The input is different from what we had before, reset the cooking time
274  if (!m_IsLoading)
275  {
276  m_TimeCooked = 0;
277  }
278  }
280 
283  if (!CanCookInputToOutput())
284  {
285  // This input cannot be cooked, reset cook counter immediately
286  SetCookTimes(0, 0);
287  SetIsCooking(false);
288  }
289  else
290  {
292 
293  // Start burning new fuel if there's no flame now:
294  if (GetFuelBurnTimeLeft() <= 0)
295  {
296  BurnNewFuel();
297  }
298  // Already burning, set cooking to ensure that cooking is occuring
299  else
300  {
301  SetIsCooking(true);
302  }
303  }
304 }
305 
306 
307 
308 
309 
311 {
313  {
314  // The current fuel is still burning, don't modify anything:
315  return;
316  }
317 
318  // The current fuel is spent, try to burn some more:
319  BurnNewFuel();
320 }
321 
322 
323 
324 
325 
327 {
328  if (!CanCookInputToOutput())
329  {
330  // Cannot cook anymore:
331  SetCookTimes(0, 0);
332  SetIsCooking(false);
333  return;
334  }
335 
336  // Can cook, start cooking if not already underway:
338 
339  // Check if fuel needs to start a burn
340  if (GetFuelBurnTimeLeft() <= 0)
341  {
342  BurnNewFuel();
343  }
344  // Already burning, set cooking to ensure that cooking is occuring
345  else
346  {
347  SetIsCooking(true);
348  }
349 }
350 
351 
352 
353 
354 
356 {
357  if (m_CurrentRecipe == nullptr)
358  {
359  // This input cannot be cooked
360  return false;
361  }
362 
363  const cItem & Slot = m_Contents.GetSlot(fsOutput);
364  if (Slot.IsEmpty())
365  {
366  // The output is empty, can cook
367  return true;
368  }
369 
370  if (!Slot.IsEqual(*m_CurrentRecipe->Out))
371  {
372  // The output slot is blocked with something that cannot be stacked with the recipe's output
373  return false;
374  }
375 
376  if (Slot.IsFullStack())
377  {
378  // Cannot add any more items to the output slot
379  return false;
380  }
381 
382  return true;
383 }
384 
385 
386 
387 
388 
389 void cFurnaceEntity::UpdateProgressBars(bool a_ForceUpdate)
390 {
391  // In order to preserve bandwidth, an update is sent only every 10th tick:
392  if (!a_ForceUpdate && ((m_World->GetWorldTickAge() % 10_tick) != 0_tick))
393  {
394  return;
395  }
396 
397  int CurFuel = (m_FuelBurnTime > 0) ? 200 - (200 * m_TimeBurned / m_FuelBurnTime) : 0;
398  BroadcastProgress(PROGRESSBAR_FUEL, static_cast<short>(CurFuel));
399 
400  int CurCook = (m_NeedCookTime > 0) ? (200 * m_TimeCooked / m_NeedCookTime) : 0;
401  BroadcastProgress(PROGRESSBAR_SMELTING_CONFIRM, 200); // Post 1.8, Mojang requires a random packet with an ID of three and value of 200. Wat. Wat. Wat.
402  BroadcastProgress(PROGRESSBAR_SMELTING, static_cast<short>(CurCook));
403 }
404 
405 
406 
407 
408 
409 void cFurnaceEntity::SetIsCooking(bool a_IsCooking)
410 {
411  if (a_IsCooking == m_IsCooking)
412  {
413  return;
414  }
415  m_IsCooking = a_IsCooking;
416 
417  // Only light the furnace as it is extinguished only when the fuel runs out, not when cooking stops - handled in this::Tick()
418  if (m_IsCooking)
419  {
422  }
423 }
@ PROGRESSBAR_SMELTING_CONFIRM
@ PROGRESSBAR_FUEL
@ PROGRESSBAR_SMELTING
@ E_BLOCK_FURNACE
Definition: BlockType.h:73
@ E_BLOCK_LIT_FURNACE
Definition: BlockType.h:74
@ E_ITEM_LAVA_BUCKET
Definition: BlockType.h:371
@ E_ITEM_BUCKET
Definition: BlockType.h:369
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
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default).
Definition: Globals.h:347
BLOCKTYPE m_BlockType
The blocktype representing this particular instance in the world.
Definition: BlockEntity.h:120
NIBBLETYPE m_BlockMeta
The block meta representing this particular instance in the world Mainly used for directional entitie...
Definition: BlockEntity.h:124
Vector3i GetRelPos() const
Definition: BlockEntity.h:95
Vector3i m_Pos
Position in absolute block coordinates.
Definition: BlockEntity.h:113
cWorld * m_World
Definition: BlockEntity.h:126
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.
bool CanCookInputToOutput(void) const
Returns true if the input can be cooked into output and the item counts allow for another cooking ope...
int m_FuelBurnTime
Amount of ticks that the current fuel can burn (in total); zero if no fuel burning.
bool m_IsLoading
Is the block currently being loaded into the world?
void FinishOne()
One item finished cooking.
const cFurnaceRecipe::cRecipe * m_CurrentRecipe
The recipe for the current input slot.
virtual void OnRemoveFromWorld() override
Called when the block entity object is removed from a world.
bool m_IsCooking
Set to true if the furnace is cooking an item.
int GetFuelBurnTimeLeft(void) const
Returns the time until the current fuel is depleted, in ticks.
Definition: FurnaceEntity.h:83
void UpdateOutput(void)
Called when the output slot changes.
virtual bool UsedBy(cPlayer *a_Player) override
Called when a player uses this entity; should open the UI window.
int m_NeedCookTime
Amount of ticks needed to fully cook current item.
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking.
virtual void CopyFrom(const cBlockEntity &a_Src) override
Copies all properties of a_Src into this entity, except for its m_World and location.
int m_TimeBurned
Amount of ticks that the current fuel has been burning.
cItem m_LastInput
The item that is being smelted.
cFurnaceEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld *a_World)
Constructor used for normal operation.
void SetIsCooking(bool a_IsCooking)
Sets the m_IsCooking variable, updates the furnace block type based on the value.
void UpdateInput(void)
Updates the recipe, based on the current input.
float m_RewardCounter
Running total of experience that can be picked up.
void SetBurnTimes(int a_FuelBurnTime, int a_TimeBurned)
Definition: FurnaceEntity.h:93
void SetCookTimes(int a_NeedCookTime, int a_TimeCooked)
Definition: FurnaceEntity.h:99
bool ContinueCooking(void)
Restarts cooking Used after the furnace is loaded from storage to set up the internal variables so th...
virtual void OnSlotChanged(cItemGrid *a_ItemGrid, int a_SlotNum) override
Called whenever a slot changes.
void BroadcastProgress(size_t a_ProgressbarID, short a_Value)
Sends the specified progressbar value to all clients of the window.
int m_TimeCooked
Amount of ticks that the current item has been cooking.
void UpdateFuel(void)
Called when the fuel slot changes or when the fuel is spent, burns another piece of fuel if appropria...
void BurnNewFuel(void)
Starts burning a new fuel, if possible.
virtual void SendTo(cClientHandle &a_Client) override
Sends the packet defining the block entity to the client specified.
int GetAndResetReward(void)
Calculates, resets, and returns the experience reward in this furnace.
void UpdateProgressBars(bool a_ForceUpdate=false)
Broadcasts progressbar updates, if needed.
Definition: Chunk.h:36
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta)
Definition: Chunk.cpp:1296
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
bool RandBool(double a_TrueProbability=0.5)
Return a random bool with the given probability of being true.
Definition: FastRandom.h:158
const cRecipe * GetRecipeFrom(const cItem &a_Ingredient) const
Returns a recipe for the specified input, nullptr if no recipe found.
int GetBurnTime(const cItem &a_Fuel) const
Returns the amount of time that the specified fuel burns, in ticks.
int CookTime
How long this recipe takes to smelt, in ticks.
Definition: FurnaceRecipe.h:32
float Reward
Experience reward for creating 1 of this item.
Definition: FurnaceRecipe.h:33
Definition: Item.h:37
char m_ItemCount
Definition: Item.h:164
bool IsEmpty(void) const
Returns true if the item represents an empty stack - either the type is invalid, or count is zero.
Definition: Item.h:69
bool IsEqual(const cItem &a_Item) const
Definition: Item.h:76
short m_ItemType
Definition: Item.h:163
bool IsFullStack(void) const
Returns true if the item is stacked up to its maximum stacking.
Definition: Item.cpp:198
void CopyFrom(const cItemGrid &a_Src)
Copies all items from a_Src to this grid.
Definition: ItemGrid.cpp:83
char ChangeSlotCount(int a_SlotNum, char a_AddToCount)
Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot.
Definition: ItemGrid.cpp:468
void SetSlot(int a_X, int a_Y, const cItem &a_Item)
Definition: ItemGrid.cpp:121
const cItem & GetSlot(int a_X, int a_Y) const
Definition: ItemGrid.cpp:96
void AddListener(cListener &a_Listener)
Adds a callback that gets called whenever a slot changes.
Definition: ItemGrid.cpp:809
static cRoot * Get()
Definition: Root.h:52
cFurnaceRecipe * GetFurnaceRecipe(void)
Definition: Root.h:94
std::unordered_map< CustomStatistic, StatValue > Custom
Represents a UI window.
Definition: Window.h:54
virtual void SetProperty(size_t a_Property, short a_Value)
Updates a numerical property associated with the window.
Definition: Window.cpp:406
cWindow * GetWindow(void) const
Definition: WindowOwner.h:40
void OpenWindow(cWindow *a_Window)
Definition: WindowOwner.h:34
Definition: World.h:53
cTickTimeLong GetWorldTickAge() const
Definition: World.cpp:509
void FastSetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: World.h:356