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:
parent
c9fbb43ac7
commit
429117c1f6
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user