Cuberite
A lightweight, fast and extensible game server for Minecraft
IncrementalRedstoneSimulator.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h"
3 
5 #include "BlockType.h"
6 #include "RedstoneHandler.h"
9 
10 
11 
12 
13 
15 {
16  switch (a_Block) // Call the appropriate simulator for the entry's block type
17  {
24  case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: return true;
25  default: return false;
26  }
27 }
28 
29 
30 
31 
32 
34 
35 {
36  switch (a_Block)
37  {
38  // All redstone devices, please alpha sort
43  case E_BLOCK_BIRCH_DOOR:
51  case E_BLOCK_DISPENSER:
52  case E_BLOCK_DROPPER:
53  case E_BLOCK_FENCE_GATE:
55  case E_BLOCK_HOPPER:
58  case E_BLOCK_IRON_DOOR:
62  case E_BLOCK_LEVER:
64  case E_BLOCK_NOTE_BLOCK:
65  case E_BLOCK_OBSERVER:
79  case E_BLOCK_TNT:
80  case E_BLOCK_TRAPDOOR:
86  case E_BLOCK_PISTON:
87  {
88  return true;
89  }
90  default: return false;
91  }
92 }
93 
94 
95 
96 
97 
98 void cIncrementalRedstoneSimulator::ProcessWorkItem(cChunk & Chunk, cChunk & TickingSource, const Vector3i Position)
99 {
100  BLOCKTYPE CurrentBlock;
101  NIBBLETYPE CurrentMeta;
102  Chunk.GetBlockTypeMeta(Position, CurrentBlock, CurrentMeta);
103 
104  ForEachSourceCallback Callback(Chunk, Position, CurrentBlock);
105  RedstoneHandler::ForValidSourcePositions(Chunk, Position, CurrentBlock, CurrentMeta, Callback);
106 
107  // Inform the handler to update
108  RedstoneHandler::Update(Chunk, TickingSource, Position, CurrentBlock, CurrentMeta, Callback.Power);
109 }
110 
111 
112 
113 
114 
115 void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
116 {
117  auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData());
118  for (auto & DelayInfo : ChunkData.m_MechanismDelays)
119  {
120  if ((--DelayInfo.second.first) == 0)
121  {
122  ChunkData.WakeUp(DelayInfo.first);
123  }
124  }
125 
126  // Build our work queue
127  auto & WorkQueue = ChunkData.GetActiveBlocks();
128 
129  // Process the work queue
130  while (!WorkQueue.empty())
131  {
132  // Grab the first element and remove it from the list
133  Vector3i CurrentLocation = WorkQueue.top();
134  WorkQueue.pop();
135 
136  const auto NeighbourChunk = a_Chunk->GetRelNeighborChunkAdjustCoords(CurrentLocation);
137  if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid())
138  {
139  continue;
140  }
141 
142  ProcessWorkItem(*NeighbourChunk, *a_Chunk, CurrentLocation);
143  }
144 
145  for (const auto & Position : ChunkData.AlwaysTickedPositions)
146  {
147  ChunkData.WakeUp(Position);
148  }
149 }
150 
151 
152 
153 
154 
156 {
157  // Never update blocks without a handler:
158  if (!IsRedstone(a_Block))
159  {
160  return;
161  }
162 
163  auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData());
164 
165  if (IsAlwaysTicked(a_Block))
166  {
167  ChunkData.AlwaysTickedPositions.emplace(a_Position);
168  }
169 
170  // Temporary: in the absence of block state support calculate our own:
171  if (a_Block == E_BLOCK_REDSTONE_WIRE)
172  {
173  RedstoneHandler::SetWireState(a_Chunk, a_Position);
174  }
175 
176  // Always update redstone devices:
177  ChunkData.WakeUp(a_Position);
178 }
179 
180 
181 
182 
183 
185 {
187 }
188 
189 
190 
191 
192 
194 {
195  // Having WakeUp called on us directly means someone called SetBlock (or WakeUp)
196  // Since the simulator never does this, something external changed. Clear cached data:
197  static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData())->ErasePowerData(a_Position);
198 
199  // Queue the block, in case the set block was redstone:
200  AddBlock(a_Chunk, a_Position, a_Block);
201 }
202 
203 
204 
205 
206 
207 void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, Vector3i a_Offset, BLOCKTYPE a_Block)
208 {
209  // This is an automatic cross-coords wakeup by cSimulatorManager
210  // There is no need to erase power data; if a component was destroyed the 3-arg WakeUp will handle it
211 
212  AddBlock(a_Chunk, a_Position, a_Block);
213 
214  // The only thing to do go one block farther than this cross-coord, in the direction of Offset
215  // in order to notify linked-powered positions that there was a change
216 
217  for (const auto & Offset : cSimulator::GetLinkedOffsets(a_Offset))
218  {
219  auto Relative = a_Position - a_Offset + Offset;
220 
221  if (!cChunkDef::IsValidHeight(Relative))
222  {
223  continue;
224  }
225 
226  const auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative);
227 
228  if ((Chunk == nullptr) || !Chunk->IsValid())
229  {
230  continue;
231  }
232 
233  const auto Block = Chunk->GetBlock(Relative);
234  AddBlock(*Chunk, Relative, Block);
235  }
236 }
@ E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE
Definition: BlockType.h:163
@ E_BLOCK_REDSTONE_LAMP_OFF
Definition: BlockType.h:138
@ E_BLOCK_WOODEN_BUTTON
Definition: BlockType.h:158
@ E_BLOCK_REDSTONE_TORCH_ON
Definition: BlockType.h:90
@ E_BLOCK_STONE_PRESSURE_PLATE
Definition: BlockType.h:84
@ E_BLOCK_DAYLIGHT_SENSOR
Definition: BlockType.h:167
@ E_BLOCK_REDSTONE_REPEATER_ON
Definition: BlockType.h:109
@ E_BLOCK_STICKY_PISTON
Definition: BlockType.h:39
@ E_BLOCK_TRAPDOOR
Definition: BlockType.h:111
@ E_BLOCK_ACTIVATOR_RAIL
Definition: BlockType.h:174
@ E_BLOCK_BIRCH_FENCE_GATE
Definition: BlockType.h:203
@ E_BLOCK_ACACIA_FENCE_GATE
Definition: BlockType.h:206
@ E_BLOCK_BLOCK_OF_REDSTONE
Definition: BlockType.h:168
@ E_BLOCK_OBSERVER
Definition: BlockType.h:237
@ E_BLOCK_FENCE_GATE
Definition: BlockType.h:286
@ E_BLOCK_SPRUCE_DOOR
Definition: BlockType.h:212
@ E_BLOCK_TNT
Definition: BlockType.h:56
@ E_BLOCK_BIRCH_DOOR
Definition: BlockType.h:213
@ E_BLOCK_IRON_DOOR
Definition: BlockType.h:85
@ E_BLOCK_LEVER
Definition: BlockType.h:83
@ E_BLOCK_INACTIVE_COMPARATOR
Definition: BlockType.h:165
@ E_BLOCK_JUNGLE_DOOR
Definition: BlockType.h:214
@ E_BLOCK_POWERED_RAIL
Definition: BlockType.h:37
@ E_BLOCK_ACTIVE_COMPARATOR
Definition: BlockType.h:166
@ E_BLOCK_TRAPPED_CHEST
Definition: BlockType.h:161
@ E_BLOCK_SPRUCE_FENCE_GATE
Definition: BlockType.h:202
@ E_BLOCK_DETECTOR_RAIL
Definition: BlockType.h:38
@ E_BLOCK_WOODEN_DOOR
Definition: BlockType.h:285
@ E_BLOCK_REDSTONE_WIRE
Definition: BlockType.h:65
@ E_BLOCK_DARK_OAK_FENCE_GATE
Definition: BlockType.h:205
@ E_BLOCK_JUNGLE_FENCE_GATE
Definition: BlockType.h:204
@ E_BLOCK_COMMAND_BLOCK
Definition: BlockType.h:152
@ E_BLOCK_WOODEN_PRESSURE_PLATE
Definition: BlockType.h:86
@ E_BLOCK_REDSTONE_TORCH_OFF
Definition: BlockType.h:89
@ E_BLOCK_NOTE_BLOCK
Definition: BlockType.h:35
@ E_BLOCK_DARK_OAK_DOOR
Definition: BlockType.h:216
@ E_BLOCK_ACACIA_DOOR
Definition: BlockType.h:215
@ E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE
Definition: BlockType.h:162
@ E_BLOCK_HOPPER
Definition: BlockType.h:171
@ E_BLOCK_DROPPER
Definition: BlockType.h:176
@ E_BLOCK_REDSTONE_REPEATER_OFF
Definition: BlockType.h:108
@ E_BLOCK_DISPENSER
Definition: BlockType.h:33
@ E_BLOCK_IRON_TRAPDOOR
Definition: BlockType.h:186
@ E_BLOCK_STONE_BUTTON
Definition: BlockType.h:91
@ E_BLOCK_REDSTONE_LAMP_ON
Definition: BlockType.h:139
@ E_BLOCK_INVERTED_DAYLIGHT_SENSOR
Definition: BlockType.h:197
@ E_BLOCK_TRIPWIRE_HOOK
Definition: BlockType.h:146
@ E_BLOCK_PISTON
Definition: BlockType.h:43
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
void SetWireState(const cChunk &Chunk, const Vector3i Position)
Temporary: compute and set the block state of a redstone wire.
void Update(cChunk &Chunk, cChunk &CurrentlyTicking, const Vector3i Position, const BLOCKTYPE BlockType, const NIBBLETYPE Meta, const PowerLevel PowerLevel)
Tells a redstone component at this position to update itself.
void ForValidSourcePositions(const cChunk &Chunk, const Vector3i Position, const BLOCKTYPE BlockType, const NIBBLETYPE Meta, ForEachSourceCallback &Callback)
Invokes Callback for each position this component can accept power from.
Definition: Chunk.h:36
cChunk * GetRelNeighborChunkAdjustCoords(Vector3i &a_RelPos) const
Returns the chunk into which the relatively-specified block belongs.
Definition: Chunk.cpp:1885
cRedstoneSimulatorChunkData * GetRedstoneSimulatorData(void) const
Definition: Chunk.h:416
void GetBlockTypeMeta(Vector3i a_RelPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: Chunk.cpp:1757
static bool IsValidHeight(Vector3i a_BlockPosition)
Validates a height-coordinate.
Definition: ChunkDef.h:185
static bool IsRedstone(BLOCKTYPE a_Block)
Returns if a block is any sort of redstone device.
virtual void WakeUp(cChunk &a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override
Called to simulate a single new block, typically as a result of a single block break or change.
void ProcessWorkItem(cChunk &Chunk, cChunk &TickingSource, const Vector3i Position)
virtual void AddBlock(cChunk &a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override
Called to simulate a new block.
virtual void SimulateChunk(std::chrono::milliseconds Dt, int ChunkX, int ChunkZ, cChunk *Chunk) override
static bool IsAlwaysTicked(BLOCKTYPE a_Block)
Returns if a redstone device is always ticked due to influence by its environment.
virtual cRedstoneSimulatorChunkData * CreateChunkData() override
std::unordered_set< Vector3i, VectorHasher< int > > AlwaysTickedPositions
static std::array< Vector3i, 5 > GetLinkedOffsets(Vector3i Offset)
For a given offset from a position, return the offsets that represent the adjacents of the newly offs...
Definition: Simulator.cpp:12