1
0

Doors: check power & toggle correctly

* Fixed upper half ignoring its updates
* Fixes #4945
* Fixed doors playing sound effects when they didn't actually toggle
This commit is contained in:
Tiger Wang 2020-09-28 22:04:57 +01:00
parent c9fbb43ac7
commit 429117c1f6
2 changed files with 74 additions and 43 deletions

View File

@ -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.

View File

@ -22,37 +22,6 @@ namespace DoorHandler
return 0;
}
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)
{
// We're treating the bottom half as the source of truth, so ignore updates to the top:
return;
}
const auto TopPosition = a_Position + OffsetYP;
ForEachSourceCallback Callback(a_Chunk, TopPosition, a_BlockType);
RedstoneHandler::ForValidSourcePositions(a_Chunk, TopPosition, a_BlockType, a_Meta, Callback);
// Factor in what the upper 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 auto AbsolutePosition = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
if (ShouldBeOpen != IsOpen)
{
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);
@ -60,4 +29,70 @@ namespace DoorHandler
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);
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)
{
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 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 other half is getting:
Power = std::max(Power, Callback.Power);
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());
// 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);
}
}
};