Cuberite
A lightweight, fast and extensible game server for Minecraft
PressurePlateHandler.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "../../BoundingBox.h"
5 #include "../../Entities/Pickup.h"
6 
7 
8 
9 
10 
12 {
13  static unsigned char GetPowerLevel(const cChunk & Chunk, const Vector3i Position, const BLOCKTYPE BlockType)
14  {
15  size_t NumberOfEntities = 0;
16  bool FoundPlayer = false;
17 
18  Chunk.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), [&](cEntity & Entity)
19  {
20  if (Entity.GetHealth() <= 0)
21  {
22  return false;
23  }
24 
25  if (Entity.IsPlayer())
26  {
27  const auto & Player = static_cast<cPlayer &>(Entity);
28 
29  if (Player.IsGameModeSpectator())
30  {
31  return false;
32  }
33 
34  FoundPlayer = true;
35  }
36  else if (Entity.IsPickup())
37  {
38  const auto & Pickup = static_cast<cPickup &>(Entity);
39  NumberOfEntities += static_cast<size_t>(Pickup.GetItem().m_ItemCount);
40  return false;
41  }
42 
43  NumberOfEntities++;
44  return false;
45  });
46 
47  switch (BlockType)
48  {
50  {
51  return FoundPlayer ? 15 : 0;
52  }
54  {
55  return (NumberOfEntities != 0) ? 15 : 0;
56  }
58  {
59  return std::min(static_cast<unsigned char>(CeilC(NumberOfEntities / 10.f)), static_cast<unsigned char>(15));
60  }
62  {
63  return std::min(static_cast<unsigned char>(NumberOfEntities), static_cast<unsigned char>(15));
64  }
65  default:
66  {
67  ASSERT(!"Unhandled/unimplemented block in pressure plate handler!");
68  return 0;
69  }
70  }
71  }
72 
73  static const char * GetClickOnSound(BLOCKTYPE a_BlockType)
74  {
75  // manage on-sound
76  switch (a_BlockType)
77  {
78  case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_pressureplate.click_on";
79  case E_BLOCK_WOODEN_PRESSURE_PLATE: return "block.wood_pressureplate.click_on";
81  case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_on";
82  default:
83  {
84  ASSERT(!"No on sound for this one!");
85  return "";
86  }
87  }
88  }
89 
90  static const char * GetClickOffSound(BLOCKTYPE a_BlockType)
91  {
92  // manage off-sound
93  switch (a_BlockType)
94  {
95  case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_pressureplate.click_off";
96  case E_BLOCK_WOODEN_PRESSURE_PLATE: return "block.wood_pressureplate.click_off";
98  case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_off";
99  default:
100  {
101  ASSERT(!"No off sound for this one!");
102  return "";
103  }
104  }
105  }
106 
107  static PowerLevel GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked)
108  {
109  UNUSED(a_BlockType);
110  UNUSED(a_QueryPosition);
111  UNUSED(a_QueryBlockType);
112 
113  // Plates only link power blocks below
114  // Retrieve and return the cached power calculated by Update for performance:
115  return (IsLinked && (a_QueryPosition != (a_Position + OffsetYM))) ? 0 : DataForChunk(a_Chunk).GetCachedPowerData(a_Position);
116  }
117 
118  static void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const PowerLevel Power)
119  {
120  // LOGD("Evaluating clicky the pressure plate (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
121 
122  auto & ChunkData = DataForChunk(a_Chunk);
123 
124  const auto PreviousPower = ChunkData.GetCachedPowerData(a_Position);
125  const auto Absolute = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
126  const auto PowerLevel = GetPowerLevel(a_Chunk, Absolute, a_BlockType); // Get the current power of the platey
127  const auto DelayInfo = ChunkData.GetMechanismDelayInfo(a_Position);
128 
129  // Resting state?
130  if (DelayInfo == nullptr)
131  {
132  if (PowerLevel == 0)
133  {
134  // Nothing happened, back to rest
135  return;
136  }
137 
138  // From rest, a player stepped on us
139  // Schedule a minimum 0.5 second delay before even thinking about releasing
140  ChunkData.m_MechanismDelays[a_Position] = std::make_pair(5, true);
141 
142  a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOnSound(a_BlockType), Absolute, 0.5f, 0.6f);
143 
144  // Update power
145  ChunkData.SetCachedPowerData(a_Position, PowerLevel);
146 
147  // Immediately depress plate
148  a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_DEPRESSED);
149 
150  UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
151  return;
152  }
153 
154  // Not a resting state
155 
156  int DelayTicks;
157  bool HasExitedMinimumOnDelayPhase;
158  std::tie(DelayTicks, HasExitedMinimumOnDelayPhase) = *DelayInfo;
159 
160  // Are we waiting for the initial delay or subsequent release delay?
161  if (DelayTicks > 0)
162  {
163  // Nothing changes, if there is nothing on it anymore, because the state is locked.
164  if (PowerLevel == 0)
165  {
166  return;
167  }
168 
169  // Yes. Are we waiting to release, and found that the player stepped on it again?
170  if (!HasExitedMinimumOnDelayPhase)
171  {
172  // Reset delay
173  *DelayInfo = std::make_pair(0, true);
174  }
175 
176  // Did the power level change and is still above zero?
177  if (PowerLevel != PreviousPower)
178  {
179  // Yes. Update power
180  ChunkData.SetCachedPowerData(a_Position, PowerLevel);
181  UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
182  }
183 
184  return;
185  }
186 
187  // Not waiting for anything. Has the initial delay elapsed?
188  if (HasExitedMinimumOnDelayPhase)
189  {
190  // Yep, initial delay elapsed. Has the player gotten off?
191  if (PowerLevel == 0)
192  {
193  // Yes. Go into subsequent release delay, for a further 0.5 seconds
194  *DelayInfo = std::make_pair(5, false);
195  return;
196  }
197 
198  // Did the power level change and is still above zero?
199  if (PowerLevel != PreviousPower)
200  {
201  // Yes. Update power
202  ChunkData.SetCachedPowerData(a_Position, PowerLevel);
203  UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
204  }
205 
206  // Yes, but player's still on the plate, do nothing
207  return;
208  }
209 
210  // Just got out of the subsequent release phase, reset everything and raise the plate
211  ChunkData.m_MechanismDelays.erase(a_Position);
212 
213  a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOffSound(a_BlockType), Absolute, 0.5f, 0.5f);
214  ChunkData.SetCachedPowerData(a_Position, PowerLevel);
215 
216  a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_RAISED);
217  UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
218  }
219 
220  static void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback & Callback)
221  {
222  UNUSED(a_Chunk);
223  UNUSED(a_Position);
224  UNUSED(a_BlockType);
225  UNUSED(a_Meta);
226  UNUSED(Callback);
227  }
228 };
@ E_META_PRESSURE_PLATE_DEPRESSED
Definition: BlockType.h:768
@ E_META_PRESSURE_PLATE_RAISED
Definition: BlockType.h:767
@ E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE
Definition: BlockType.h:163
@ E_BLOCK_STONE_PRESSURE_PLATE
Definition: BlockType.h:84
@ E_BLOCK_WOODEN_PRESSURE_PLATE
Definition: BlockType.h:86
@ E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE
Definition: BlockType.h:162
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
std::enable_if< std::is_arithmetic< T >::value, C >::type CeilC(T a_Value)
Ceils a value, then casts it to C (an int by default).
Definition: Globals.h:354
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
BlockType
Definition: BlockTypes.h:4
auto & DataForChunk(const cChunk &a_Chunk)
constexpr std::array< Vector3i, 6 > RelativeAdjacents
constexpr Vector3i OffsetYM
void UpdateAdjustedRelatives(const cChunk &a_Chunk, const cChunk &a_TickingChunk, const Vector3i a_Position, const ArrayType &a_Relative)
unsigned char PowerLevel
Vector3< double > Vector3d
Definition: Vector3.h:485
unsigned char Power(const BlockState Block)
static const char * GetClickOnSound(BLOCKTYPE a_BlockType)
static void ForValidSourcePositions(const cChunk &a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback &Callback)
static unsigned char GetPowerLevel(const cChunk &Chunk, const Vector3i Position, const BLOCKTYPE BlockType)
static void Update(cChunk &a_Chunk, cChunk &CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const PowerLevel Power)
static PowerLevel GetPowerDeliveredToPosition(const cChunk &a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked)
static const char * GetClickOffSound(BLOCKTYPE a_BlockType)
Represents two sets of coords, minimum and maximum for each direction.
Definition: BoundingBox.h:24
Definition: Chunk.h:36
cChunkCoords GetPos() const
Definition: Chunk.h:133
bool ForEachEntityInBox(const cBoundingBox &a_Box, cEntityCallback a_Callback) const
Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Definition: Chunk.cpp:1674
void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
Definition: Chunk.h:286
cWorld * GetWorld(void) const
Definition: Chunk.h:135
static Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition, cChunkCoords a_ChunkCoords)
Converts relative block coordinates into absolute coordinates with a known chunk location.
Definition: ChunkDef.h:174
Definition: Entity.h:76
bool IsPlayer(void) const
Definition: Entity.h:160
bool IsPickup(void) const
Definition: Entity.h:161
float GetHealth(void) const
Returns the health of this entity.
Definition: Entity.h:367
virtual void BroadcastSoundEffect(const AString &a_SoundName, Vector3d a_Position, float a_Volume, float a_Pitch, const cClientHandle *a_Exclude=nullptr) override