Cuberite
A lightweight, fast and extensible game server for Minecraft
RedstoneComparatorHandler.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "../../Blocks/BlockComparator.h"
5 
6 
7 
8 
9 
11 {
12  static unsigned char GetFrontPowerLevel(NIBBLETYPE a_Meta, unsigned char a_HighestSidePowerLevel, unsigned char a_HighestRearPowerLevel)
13  {
15  {
16  // Subtraction mode
17  return static_cast<unsigned char>(std::max(static_cast<char>(a_HighestRearPowerLevel) - a_HighestSidePowerLevel, 0));
18  }
19  else
20  {
21  // Comparison mode
22  return (a_HighestRearPowerLevel < a_HighestSidePowerLevel) ? 0 : a_HighestRearPowerLevel;
23  }
24  }
25 
26  static PowerLevel GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked)
27  {
28  UNUSED(a_QueryPosition);
29  UNUSED(a_QueryBlockType);
30 
31  const auto Meta = a_Chunk.GetMeta(a_Position);
32  return (
33  (cBlockComparatorHandler::GetFrontCoordinate(a_Position, Meta & 0x3) == a_QueryPosition) ?
34  DataForChunk(a_Chunk).GetCachedPowerData(a_Position) : 0
35  );
36  }
37 
38  static unsigned char GetPowerLevel(cChunk & a_Chunk, Vector3i Position, BLOCKTYPE BlockType, NIBBLETYPE Meta)
39  {
40  UInt8 SignalStrength = 0;
41  auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(Position, Meta & 0x3);
42 
43  auto RearChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RearCoordinate);
44  if ((RearChunk == nullptr) || !RearChunk->IsValid())
45  {
46  return SignalStrength;
47  }
48 
49  RearChunk->DoWithBlockEntityAt(RearCoordinate, [&](cBlockEntity & a_BlockEntity)
50  {
51  // Skip BlockEntities that don't have slots
52  auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(&a_BlockEntity);
53  if (BlockEntityWithItems == nullptr)
54  {
55  return false;
56  }
57 
58  // TODO: handle double chests
59 
60  auto & Contents = BlockEntityWithItems->GetContents();
61  float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value
62 
63  for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot)
64  {
65  Fullness += static_cast<float>(Contents.GetSlot(Slot).m_ItemCount) / Contents.GetSlot(Slot).GetMaxStackSize();
66  }
67 
68  SignalStrength = (Fullness < 0.001 /* container empty? */) ? 0 : static_cast<UInt8>(1 + (Fullness / Contents.GetNumSlots()) * 14);
69  return false;
70  });
71 
72  const auto RearType = RearChunk->GetBlock(RearCoordinate);
73  return std::max(
74  SignalStrength,
76  *RearChunk, RearCoordinate, RearType,
78  )
79  );
80  }
81 
82  static void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const PowerLevel Power)
83  {
84  // Note that Power here contains the maximum * side * power level, as specified by GetValidSourcePositions
85  // LOGD("Evaluating ALU the comparator (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
86 
87  auto & Data = DataForChunk(a_Chunk);
88  auto DelayInfo = Data.GetMechanismDelayInfo(a_Position);
89 
90  // Delay is used here to prevent an infinite loop (#3168)
91  if (DelayInfo == nullptr)
92  {
93  const auto RearPower = GetPowerLevel(a_Chunk, a_Position, a_BlockType, a_Meta);
94  const auto FrontPower = GetFrontPowerLevel(a_Meta, Power, RearPower);
95  const auto PreviousFrontPower = Data.GetCachedPowerData(a_Position);
96  const bool ShouldUpdate = (FrontPower != PreviousFrontPower); // "Business logic" (:P) - determined by side and rear power levels
97 
98  if (ShouldUpdate)
99  {
100  Data.m_MechanismDelays[a_Position] = std::make_pair(1, bool());
101  }
102 
103  return;
104  }
105 
106  int DelayTicks;
107  std::tie(DelayTicks, std::ignore) = *DelayInfo;
108 
109  if (DelayTicks != 0)
110  {
111  return;
112  }
113 
114  const auto RearPower = GetPowerLevel(a_Chunk, a_Position, a_BlockType, a_Meta);
115  const auto FrontPower = GetFrontPowerLevel(a_Meta, Power, RearPower);
116  const NIBBLETYPE NewMeta = (FrontPower > 0) ? (a_Meta | 0x08u) : (a_Meta & 0x07u);
117 
118  // Don't care about the previous power level so return value ignored
119  Data.ExchangeUpdateOncePowerData(a_Position, FrontPower);
120 
121  a_Chunk.SetMeta(a_Position, NewMeta);
122  Data.m_MechanismDelays.erase(a_Position);
123 
124  // Assume that an update (to front power) is needed:
125  UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3) - a_Position);
126  }
127 
128  static void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback & Callback)
129  {
130  UNUSED(a_Chunk);
131  UNUSED(a_BlockType);
132 
133  Callback(cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, false));
134  Callback(cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, true));
135  }
136 };
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
unsigned char UInt8
Definition: Globals.h:159
#define UNUSED
Definition: Globals.h:72
BlockType
Definition: BlockTypes.h:4
auto & DataForChunk(const cChunk &a_Chunk)
void UpdateAdjustedRelative(const cChunk &a_Chunk, const cChunk &a_TickingChunk, const Vector3i a_Position, const Vector3i a_Offset)
unsigned char PowerLevel
unsigned char Power(const BlockState Block)
static unsigned char GetPowerLevel(cChunk &a_Chunk, Vector3i Position, BLOCKTYPE BlockType, NIBBLETYPE Meta)
static PowerLevel GetPowerDeliveredToPosition(const cChunk &a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked)
static unsigned char GetFrontPowerLevel(NIBBLETYPE a_Meta, unsigned char a_HighestSidePowerLevel, unsigned char a_HighestRearPowerLevel)
static void Update(cChunk &a_Chunk, cChunk &CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const PowerLevel Power)
static void ForValidSourcePositions(const cChunk &a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback &Callback)
PowerLevel GetPowerDeliveredToPosition(const cChunk &Chunk, const Vector3i Position, const BLOCKTYPE BlockType, const Vector3i QueryPosition, const BLOCKTYPE QueryBlockType, const bool IsLinked)
Asks a redstone component at the source position how much power it will deliver to the querying posit...
cItemGrid & GetContents(void)
Returns the ItemGrid used for storing the contents.
static Vector3i GetRearCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
static Vector3i GetSideCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta, bool a_bInverse)
static Vector3i GetFrontCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
static bool IsInSubtractionMode(NIBBLETYPE a_Meta)
Definition: Chunk.h:36
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:279
bool DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback)
Calls the callback for the block entity at the specified coords; returns false if there's no block en...
Definition: Chunk.cpp:1737
cChunk * GetRelNeighborChunkAdjustCoords(Vector3i &a_RelPos) const
Returns the chunk into which the relatively-specified block belongs.
Definition: Chunk.cpp:1885
void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
Definition: Chunk.h:286
char GetMaxStackSize(void) const
Returns the maximum amount of stacked items of this type.
Definition: Item.cpp:207
const cItem & GetSlot(int a_X, int a_Y) const
Definition: ItemGrid.cpp:96
static Vector3i RebaseRelativePosition(const cChunk &From, const cChunk &To, const Vector3i Position)
Adjust From-relative coordinates into To-relative coordinates.