Cuberite
A lightweight, fast and extensible game server for Minecraft
ItemBucket.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "ItemHandler.h"
5 #include "../World.h"
6 #include "../Simulator/FluidSimulator.h"
7 #include "../Blocks/BlockHandler.h"
8 #include "../LineBlockTracer.h"
9 #include "../Blocks/ChunkInterface.h"
10 
11 
12 
13 
14 
16  public cItemHandler
17 {
18 public:
19  cItemBucketHandler(int a_ItemType) :
20  cItemHandler(a_ItemType)
21  {
22 
23  }
24 
25 
26 
27  virtual bool OnItemUse(
28  cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
29  int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
30  ) override
31  {
32  switch (m_ItemType)
33  {
34  case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
35  case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_LAVA);
36  case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_WATER);
37  default:
38  {
39  ASSERT(!"Unhandled ItemType");
40  return false;
41  }
42  }
43  }
44 
45 
46 
47  bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
48  {
49  // Players can't pick up fluid while in adventure mode.
50  if (a_Player->IsGameModeAdventure())
51  {
52  return false;
53  }
54 
55  if (a_BlockFace != BLOCK_FACE_NONE)
56  {
57  return false;
58  }
59 
60  Vector3i BlockPos;
61  if (!GetBlockFromTrace(a_World, a_Player, BlockPos))
62  {
63  return false; // Nothing in range.
64  }
65 
66  if (a_World->GetBlockMeta(BlockPos.x, BlockPos.y, BlockPos.z) != 0)
67  {
68  // Not a source block
69  return false;
70  }
71 
72  BLOCKTYPE Block = a_World->GetBlock(BlockPos.x, BlockPos.y, BlockPos.z);
73  ENUM_ITEM_ID NewItem;
74 
75  if (IsBlockWater(Block))
76  {
77  NewItem = E_ITEM_WATER_BUCKET;
78  }
79  else if (IsBlockLava(Block))
80  {
81  NewItem = E_ITEM_LAVA_BUCKET;
82  }
83  else
84  {
85  return false;
86  }
87 
88  // Check to see if destination block is too far away
89  // Reach Distance Multiplayer = 5 Blocks
90  if ((BlockPos.x - a_Player->GetPosX() > 5) || (BlockPos.z - a_Player->GetPosZ() > 5))
91  {
92  return false;
93  }
94 
95  // Remove water / lava block (unless plugins disagree)
96  if (!a_Player->PlaceBlock(BlockPos.x, BlockPos.y, BlockPos.z, E_BLOCK_AIR, 0))
97  {
98  return false;
99  }
100 
101  // Give new bucket, filled with fluid when the gamemode is not creative:
102  if (!a_Player->IsGameModeCreative())
103  {
104  // Remove the bucket from the inventory
105  if (!a_Player->GetInventory().RemoveOneEquippedItem())
106  {
107  LOG("Clicked with an empty bucket, but cannot remove one from the inventory? WTF?");
108  ASSERT(!"Inventory bucket mismatch");
109  return true;
110  }
111  if (a_Player->GetInventory().AddItem(cItem(NewItem)) != 1)
112  {
113  // The bucket didn't fit, toss it as a pickup:
114  a_Player->TossPickup(cItem(NewItem));
115  }
116  }
117 
118  return true;
119  }
120 
121 
122 
123 
124 
126  cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
127  int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock
128  )
129  {
130  // Players can't place fluid while in adventure mode.
131  if (a_Player->IsGameModeAdventure())
132  {
133  return false;
134  }
135 
136  if (a_BlockFace != BLOCK_FACE_NONE)
137  {
138  return false;
139  }
140 
141  BLOCKTYPE CurrentBlockType;
142  NIBBLETYPE CurrentBlockMeta;
143  eBlockFace EntryFace;
144  Vector3i BlockPos;
145  if (!GetPlacementCoordsFromTrace(a_World, a_Player, BlockPos, CurrentBlockType, CurrentBlockMeta, EntryFace))
146  {
147  return false;
148  }
149 
150  // Check to see if destination block is too far away
151  // Reach Distance Multiplayer = 5 Blocks
152  if ((BlockPos.x - a_Player->GetPosX() > 5) || (BlockPos.z - a_Player->GetPosZ() > 5))
153  {
154  return false;
155  }
156 
157  if (!a_Player->IsGameModeCreative())
158  {
159  // Remove fluid bucket, add empty bucket:
160  if (!a_Player->GetInventory().RemoveOneEquippedItem())
161  {
162  LOG("Clicked with a full bucket, but cannot remove one from the inventory? WTF?");
163  ASSERT(!"Inventory bucket mismatch");
164  return false;
165  }
166  cItem Item(E_ITEM_BUCKET, 1);
167  if (!a_Player->GetInventory().AddItem(Item))
168  {
169  return false;
170  }
171  }
172 
173  // Wash away anything that was there prior to placing:
174  if (cFluidSimulator::CanWashAway(CurrentBlockType))
175  {
176  if (a_PluginInterface.CallHookPlayerBreakingBlock(*a_Player, BlockPos.x, BlockPos.y, BlockPos.z, EntryFace, CurrentBlockType, CurrentBlockMeta))
177  {
178  // Plugin disagrees with the washing-away
179  return false;
180  }
181  a_World->DropBlockAsPickups(BlockPos, a_Player, nullptr);
182  a_PluginInterface.CallHookPlayerBrokenBlock(*a_Player, BlockPos.x, BlockPos.y, BlockPos.z, EntryFace, CurrentBlockType, CurrentBlockMeta);
183  }
184 
185  // Place the actual fluid block:
186  return a_Player->PlaceBlock(BlockPos.x, BlockPos.y, BlockPos.z, a_FluidBlock, 0);
187  }
188 
189 
190 
191 
192 
193  bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos)
194  {
195  class cCallbacks :
196  public cBlockTracer::cCallbacks
197  {
198  public:
199  Vector3i m_Pos;
200  bool m_HasHitFluid;
201 
202 
203  cCallbacks(void) :
204  m_HasHitFluid(false)
205  {
206  }
207 
208  virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
209  {
210  if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType))
211  {
212  if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source
213  {
214  return false;
215  }
216  m_HasHitFluid = true;
217  m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ);
218  return true;
219  }
220  return false;
221  }
222  } Callbacks;
223 
224  cLineBlockTracer Tracer(*a_World, Callbacks);
225  Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
226  Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
227 
228  Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
229 
230  if (!Callbacks.m_HasHitFluid)
231  {
232  return false;
233  }
234 
235 
236  a_BlockPos = Callbacks.m_Pos;
237  return true;
238  }
239 
240 
241 
242  bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta, eBlockFace & a_BlockFace)
243  {
244  class cCallbacks :
245  public cBlockTracer::cCallbacks
246  {
247  public:
248  Vector3i m_Pos;
249  BLOCKTYPE m_ReplacedBlockType;
250  NIBBLETYPE m_ReplacedBlockMeta;
251  eBlockFace m_EntryFace;
252 
253  virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
254  {
255  if ((a_CBBlockType != E_BLOCK_AIR) && !IsBlockLiquid(a_CBBlockType))
256  {
257  m_ReplacedBlockType = a_CBBlockType;
258  m_ReplacedBlockMeta = a_CBBlockMeta;
259  m_EntryFace = static_cast<eBlockFace>(a_CBEntryFace);
260  if (!cFluidSimulator::CanWashAway(a_CBBlockType))
261  {
262  AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, a_CBEntryFace); // Was an unwashawayable block, can't overwrite it!
263  }
264  m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); // (Block could be washed away, replace it)
265  return true; // Abort tracing
266  }
267  return false;
268  }
269  } Callbacks;
270 
271  cLineBlockTracer Tracer(*a_World, Callbacks);
272  Vector3d Start(a_Player->GetEyePosition());
273  Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
274 
275  // cLineBlockTracer::Trace() returns true when whole line was traversed. By returning true from the callback when we hit something,
276  // we ensure that this never happens if liquid could be placed
277  // Use this to judge whether the position is valid
278  if (!Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z))
279  {
280  a_BlockPos = Callbacks.m_Pos;
281  a_BlockType = Callbacks.m_ReplacedBlockType;
282  a_BlockMeta = Callbacks.m_ReplacedBlockMeta;
283  a_BlockFace = Callbacks.m_EntryFace;
284  return true;
285  }
286 
287  return false;
288  }
289 };
double GetPosX(void) const
Definition: Entity.h:206
BLOCKTYPE GetBlock(Vector3i a_BlockPos)
Returns the block type at the specified position.
Definition: World.h:416
T x
Definition: Vector3.h:17
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: Defines.h:436
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
bool RemoveOneEquippedItem(void)
Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed.
Definition: Inventory.cpp:207
bool ScoopUpFluid(cWorld *a_World, cPlayer *a_Player, const cItem &a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
Definition: ItemBucket.h:47
bool GetBlockFromTrace(cWorld *a_World, cPlayer *a_Player, Vector3i &a_BlockPos)
Definition: ItemBucket.h:193
Definition: Player.h:27
virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cBlockPluginInterface &a_PluginInterface, const cItem &a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
Called when the player tries to use the item (right mouse button).
Definition: ItemBucket.h:27
void Set(T a_x, T a_y, T a_z)
Definition: Vector3.h:37
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
bool PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Calls the block-placement hook and places the block in the world, unless refused by the hook...
Definition: Player.cpp:2671
bool DropBlockAsPickups(Vector3i a_BlockPos, const cEntity *a_Digger=nullptr, const cItem *a_Tool=nullptr)
Digs the specified block, and spawns the appropriate pickups for it.
Definition: World.cpp:2200
T y
Definition: Vector3.h:17
NIBBLETYPE GetBlockMeta(Vector3i a_BlockPos)
Returns the block meta at the specified position.
Definition: World.h:431
T z
Definition: Vector3.h:17
bool GetPlacementCoordsFromTrace(cWorld *a_World, cPlayer *a_Player, Vector3i &a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta, eBlockFace &a_BlockFace)
Definition: ItemBucket.h:242
static bool CanWashAway(BLOCKTYPE a_BlockType)
This interface is used to decouple block handlers from the cPluginManager dependency through cWorld...
bool IsBlockLiquid(BLOCKTYPE a_BlockType)
Definition: Defines.h:484
bool IsGameModeAdventure(void) const
Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current wor...
Definition: Player.cpp:1278
void AddFaceDirection(int &a_BlockX, int &a_BlockY, int &a_BlockZ, eBlockFace a_BlockFace, bool a_bInverse=false)
Definition: Defines.h:859
Vector3d GetLookVector(void) const
Definition: Entity.cpp:2209
Definition: World.h:65
virtual bool CallHookPlayerBrokenBlock(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)=0
#define ASSERT(x)
Definition: Globals.h:335
int AddItem(const cItem &a_ItemStack, bool a_AllowNewStacks=true)
Adds as many items out of a_ItemStack as can fit.
Definition: Inventory.cpp:106
cItemBucketHandler(int a_ItemType)
Definition: ItemBucket.h:19
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc...
Definition: Defines.h:29
bool Trace(double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ)
Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits...
void TossPickup(const cItem &a_Item)
tosses a pickup newly created from a_Item
Definition: Player.cpp:1975
virtual bool CallHookPlayerBreakingBlock(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)=0
void LOG(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:156
ENUM_ITEM_ID
Definition: BlockID.h:293
Vector3d GetEyePosition(void) const
Definition: Player.cpp:1251
double GetPosZ(void) const
Definition: Entity.h:208
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1260
bool PlaceFluid(cWorld *a_World, cPlayer *a_Player, cBlockPluginInterface &a_PluginInterface, const cItem &a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock)
Definition: ItemBucket.h:125
cInventory & GetInventory(void)
Definition: Player.h:136
Definition: Item.h:36
bool IsBlockLava(BLOCKTYPE a_BlockType)
Definition: Defines.h:475