summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Blocks/BlockDoor.h20
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h75
2 files changed, 63 insertions, 32 deletions
diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h
index 36dc788aa..ee511a290 100644
--- a/src/Blocks/BlockDoor.h
+++ b/src/Blocks/BlockDoor.h
@@ -96,6 +96,14 @@ public:
}
}
+ /** Returns true iff the door at the specified coords is open.
+ The coords may point to either the top part or the bottom part of the door. */
+ static bool IsOpen(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos)
+ {
+ const auto Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockPos);
+ return (Meta & 0x04) != 0;
+ }
+
/** Sets the door to the specified state. If the door is already in that state, does nothing. */
static void SetOpen(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos, bool a_Open)
{
@@ -237,18 +245,6 @@ private:
- /** Returns true iff the door at the specified coords is open.
- The coords may point to either the top part or the bottom part of the door. */
- static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos)
- {
- NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockPos);
- return ((Meta & 0x04) != 0);
- }
-
-
-
-
-
/** Returns the complete meta composed from the both parts of the door as (TopMeta << 4) | BottomMeta
The coords may point to either part of the door.
The returned value has bit 3 (0x08) set iff the coords point to the top part of the door.
diff --git a/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h
index fa5debbbf..00fd8c7eb 100644
--- a/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h
+++ b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h
@@ -22,42 +22,77 @@ namespace DoorHandler
return 0;
}
+ inline void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback & Callback)
+ {
+ UNUSED(a_Chunk);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
+ }
+
inline void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PowerLevel Power)
{
// LOGD("Evaluating dori the door (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
- if ((a_Meta & 0x8) == 0x8)
+ NIBBLETYPE TopMeta;
+ const bool IsTop = (a_Meta & 0x8) == 0x8;
+ const auto TopPosition = IsTop ? a_Position : a_Position.addedY(1);
+
+ // Figure out the metadata of the top half, which stores the previous redstone power state:
+ if (IsTop)
{
- // We're treating the bottom half as the source of truth, so ignore updates to the top:
- return;
+ TopMeta = a_Meta;
+ }
+ else
+ {
+ if (TopPosition.y == cChunkDef::Height)
+ {
+ return;
+ }
+
+ BLOCKTYPE AboveType;
+ a_Chunk.GetBlockTypeMeta(TopPosition, AboveType, TopMeta);
+ if (!cBlockDoorHandler::IsDoorBlockType(AboveType))
+ {
+ return;
+ }
}
- const auto TopPosition = a_Position + OffsetYP;
- ForEachSourceCallback Callback(a_Chunk, TopPosition, a_BlockType);
- RedstoneHandler::ForValidSourcePositions(a_Chunk, TopPosition, a_BlockType, a_Meta, Callback);
+ const auto OppositeHalfPosition = a_Position + (IsTop ? OffsetYM : OffsetYP);
+ ForEachSourceCallback Callback(a_Chunk, OppositeHalfPosition, a_BlockType);
+ ForValidSourcePositions(a_Chunk, OppositeHalfPosition, a_BlockType, a_Meta, Callback);
- // Factor in what the upper half is getting:
+ // Factor in what the other half is getting:
Power = std::max(Power, Callback.Power);
- cChunkInterface ChunkInterface(a_Chunk.GetWorld()->GetChunkMap());
- // Use redstone data rather than block state so players can override redstone control
- const auto Previous = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, Power);
- const bool IsOpen = (Previous != 0);
const bool ShouldBeOpen = Power != 0;
+ const bool PreviouslyPowered = (TopMeta & 0x2) == 0x2;
+
+ // Allow players to override redstone control
+ // don't update if redstone power hasn't changed since we last saw it:
+ if (ShouldBeOpen == PreviouslyPowered)
+ {
+ return;
+ }
+
+ // Update the previous redstone power:
+ if (ShouldBeOpen)
+ {
+ a_Chunk.SetMeta(TopPosition, TopMeta | 0x2);
+ }
+ else
+ {
+ a_Chunk.SetMeta(TopPosition, TopMeta & ~0x2);
+ }
+
+ cChunkInterface ChunkInterface(a_Chunk.GetWorld()->GetChunkMap());
const auto AbsolutePosition = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
- if (ShouldBeOpen != IsOpen)
+ // Toggle the door, if it needs to be changed:
+ if (ShouldBeOpen != cBlockDoorHandler::IsOpen(ChunkInterface, AbsolutePosition))
{
cBlockDoorHandler::SetOpen(ChunkInterface, AbsolutePosition, ShouldBeOpen);
a_Chunk.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, AbsolutePosition, 0);
}
}
-
- inline void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback & Callback)
- {
- UNUSED(a_Chunk);
- UNUSED(a_BlockType);
- UNUSED(a_Meta);
- InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
- }
};