From 675b4aa878f16291ce33fced48a2bc7425f635ae Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sun, 24 Nov 2013 14:19:41 +0000 Subject: Moved source to src --- src/Simulator/RedstoneSimulator.cpp | 1178 +++++++++++++++++++++++++++++++++++ 1 file changed, 1178 insertions(+) create mode 100644 src/Simulator/RedstoneSimulator.cpp (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp new file mode 100644 index 000000000..8526a888e --- /dev/null +++ b/src/Simulator/RedstoneSimulator.cpp @@ -0,0 +1,1178 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "RedstoneSimulator.h" +#include "../BlockEntities/DropSpenserEntity.h" +#include "../Blocks/BlockTorch.h" +#include "../Piston.h" +#include "../World.h" +#include "../BlockID.h" +#include "../Chunk.h" +#include "../Entities/TNTEntity.h" + + + + + +cRedstoneSimulator::cRedstoneSimulator(cWorld & a_World) + : super(a_World) +{ +} + + + + + +cRedstoneSimulator::~cRedstoneSimulator() +{ +} + + + + + +void cRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +{ + if (a_Chunk == NULL) + { + return; + } + int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; + + // Check if any close neighbor is redstone-related: + int MinY = (a_BlockY > 0) ? -1 : 0; + int MaxY = (a_BlockY < cChunkDef::Height - 1) ? 1 : 0; + for (int y = MinY; y <= MaxY; y++) for (int x = -1; x < 2; x++) for (int z = -1; z < 2; z++) + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if (!a_Chunk->UnboundedRelGetBlock(RelX + x, a_BlockY + y, RelZ + z, BlockType, BlockMeta)) + { + continue; + } + switch (BlockType) + { + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_WIRE: + case E_BLOCK_LEVER: + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_WOODEN_BUTTON: + case E_BLOCK_TRIPWIRE_HOOK: + { + m_Blocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + return; + } + } // switch (BlockType) + } // for y, x, z - neighbors +} + + + + + +void cRedstoneSimulator::Simulate(float a_Dt) +{ + // Toggle torches on/off + while (!m_RefreshTorchesAround.empty()) + { + Vector3i pos = m_RefreshTorchesAround.front(); + m_RefreshTorchesAround.pop_front(); + + RefreshTorchesAround(pos); + } + + // Set repeaters to correct values, and decrement ticks + for (RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end();) + { + if (--itr->Ticks > 0) + { + // Not yet, move to next item in the list + ++itr; + continue; + } + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + m_World.GetBlockTypeMeta(itr->Position.x, itr->Position.y, itr->Position.z, BlockType, BlockMeta); + if (itr->bPowerOn && (BlockType == E_BLOCK_REDSTONE_REPEATER_OFF)) + { + m_World.FastSetBlock(itr->Position.x, itr->Position.y, itr->Position.z, E_BLOCK_REDSTONE_REPEATER_ON, BlockMeta); + m_Blocks.push_back(itr->Position); + } + else if (!itr->bPowerOn && (BlockType == E_BLOCK_REDSTONE_REPEATER_ON)) + { + m_World.FastSetBlock(itr->Position.x, itr->Position.y, itr->Position.z, E_BLOCK_REDSTONE_REPEATER_OFF, BlockMeta); + m_Blocks.push_back(itr->Position); + } + + if (itr->bPowerOffNextTime) + { + itr->bPowerOn = false; + itr->bPowerOffNextTime = false; + itr->Ticks = 10; // TODO: Look up actual ticks from block metadata + ++itr; + } + else + { + itr = m_SetRepeaters.erase(itr); + } + } + + // Handle changed blocks + { + cCSLock Lock(m_CS); + std::swap(m_Blocks, m_BlocksBuffer); + } + for (BlockList::iterator itr = m_BlocksBuffer.begin(); itr != m_BlocksBuffer.end(); ++itr) + { + HandleChange(*itr); + } + m_BlocksBuffer.clear(); +} + + + + + +void cRedstoneSimulator::RefreshTorchesAround(const Vector3i & a_BlockPos) +{ + static Vector3i Surroundings [] = { + Vector3i(-1, 0, 0), + Vector3i(1, 0, 0), + Vector3i(0, 0,-1), + Vector3i(0, 0, 1), + Vector3i(0, 1, 0), // Also toggle torch on top + }; + BLOCKTYPE TargetBlockType = E_BLOCK_REDSTONE_TORCH_ON; + BLOCKTYPE TargetRepeaterType = E_BLOCK_REDSTONE_REPEATER_OFF; + if (IsPowered(a_BlockPos, true)) + { + TargetBlockType = E_BLOCK_REDSTONE_TORCH_OFF; + TargetRepeaterType = E_BLOCK_REDSTONE_REPEATER_ON; + //Make TNT Explode when it gets powered. + if (m_World.GetBlock(a_BlockPos) == E_BLOCK_TNT) + { + m_World.BroadcastSoundEffect("random.fuse", a_BlockPos.x * 8, a_BlockPos.y * 8, a_BlockPos.z * 8, 0.5f, 0.6f); + m_World.SpawnPrimedTNT(a_BlockPos.x + 0.5, a_BlockPos.y + 0.5, a_BlockPos.z + 0.5, 4); // 4 seconds to boom + m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_AIR, 0); + } + //Turn a redstone lamp on when it gets powered. + if (m_World.GetBlock(a_BlockPos) == E_BLOCK_REDSTONE_LAMP_OFF) + { + m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_ON, 0); + } + //if (m_World.GetBlock(a_BlockPos) == E_BLOCK_DIRT) + //{ + // m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_STONE, 0); + //} + } + else + { + //Turn a redstone lamp off when it gets powered. + if (m_World.GetBlock(a_BlockPos) == E_BLOCK_REDSTONE_LAMP_ON) + { + m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_OFF, 0); + } + //if (m_World.GetBlock(a_BlockPos) == E_BLOCK_STONE) + //{ + // m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_DIRT, 0); + //} + } + + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i TorchPos = a_BlockPos + Surroundings[i]; + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + m_World.GetBlockTypeMeta(TorchPos.x, TorchPos.y, TorchPos.z, BlockType, BlockMeta); + switch (BlockType) + { + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_TORCH_OFF: + { + if (BlockType != TargetBlockType) + { + if (cBlockTorchHandler::IsAttachedTo(TorchPos, BlockMeta, a_BlockPos)) + { + m_World.FastSetBlock(TorchPos.x, TorchPos.y, TorchPos.z, TargetBlockType, BlockMeta); + m_Blocks.push_back(TorchPos); + } + } + break; + } + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + { + if ((BlockType != TargetRepeaterType) && IsRepeaterPointingAway(TorchPos, BlockMeta, a_BlockPos)) + { + SetRepeater(TorchPos, 10, (TargetRepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)); + } + break; + } + } // switch (BlockType) + } // for i - Surroundings[] +} + + + + + +void cRedstoneSimulator::HandleChange(const Vector3i & a_BlockPos) +{ + std::deque< Vector3i > SpreadStack; + + static const Vector3i Surroundings[] = { + Vector3i(1, 0, 0), + Vector3i(1, 1, 0), + Vector3i(1,-1, 0), + Vector3i(-1, 0, 0), + Vector3i(-1, 1, 0), + Vector3i(-1,-1, 0), + Vector3i(0, 0, 1), + Vector3i(0, 1, 1), + Vector3i(0,-1, 1), + Vector3i(0, 0,-1), + Vector3i(0, 1,-1), + Vector3i(0,-1,-1), + Vector3i(0,-1, 0), + }; + + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); + + // First check whether torch should be on or off + switch (BlockType) + { + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_TORCH_OFF: + { + static const Vector3i Surroundings [] = { + Vector3i(-1, 0, 0), + Vector3i(1, 0, 0), + Vector3i(0, 0,-1), + Vector3i(0, 0, 1), + Vector3i(0,-1, 0), + }; + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i pos = a_BlockPos + Surroundings[i]; + BLOCKTYPE OtherBlock = m_World.GetBlock(pos); + if ( + (OtherBlock != E_BLOCK_AIR) && + (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && + (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) + ) + { + RefreshTorchesAround(pos); + } + } + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); + break; + } // case "torches" + + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + { + // Check if repeater is powered by a 'powered block' (not wires/torch) + Vector3i Direction = GetRepeaterDirection(BlockMeta); + Vector3i pos = a_BlockPos - Direction; // NOTE: It's minus Direction + BLOCKTYPE OtherBlock = m_World.GetBlock(pos); + if ( + (OtherBlock != E_BLOCK_AIR) && + (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && + (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) && + (OtherBlock != E_BLOCK_REDSTONE_WIRE) + ) + { + RefreshTorchesAround(pos); + } + else + { + SetRepeater(a_BlockPos, 10, IsPowered(a_BlockPos, false)); + } + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); + break; + } + } // switch (BlockType) + + BlockList Sources; + switch (BlockType) + { + case E_BLOCK_REDSTONE_TORCH_ON: + { + // If torch is still on, use it as a source + Sources.push_back(a_BlockPos); + break; + } + + case E_BLOCK_REDSTONE_REPEATER_ON: + { + // Repeater only spreads charge right in front, and up to one block up: + static const Vector3i Surroundings [] = { + Vector3i(0, 0, 0), + Vector3i(0, 1, 0), + }; + Vector3i Direction = GetRepeaterDirection(BlockMeta); + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i pos = a_BlockPos + Direction + Surroundings[i]; + if (PowerBlock(pos, a_BlockPos, 0xf)) + { + SpreadStack.push_back(pos); + } + } + break; + } // case E_BLOCK_REDSTONE_REPEATER_ON + + case E_BLOCK_LEVER: + { + // Adding lever to the source queue + if (cRedstoneSimulator::IsLeverOn(BlockMeta)) + { + Sources.push_back(a_BlockPos); + } + break; + } // case E_BLOCK_LEVER + } // switch (BlockType) + + // Power all blocks legally connected to the sources + if (BlockType != E_BLOCK_REDSTONE_REPEATER_ON) + { + BlockList NewSources = RemoveCurrent(a_BlockPos); + Sources.insert(Sources.end(), NewSources.begin(), NewSources.end()); + while (!Sources.empty()) + { + Vector3i SourcePos = Sources.back(); + Sources.pop_back(); + + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + m_World.GetBlockTypeMeta(SourcePos.x, SourcePos.y, SourcePos.z, BlockType, BlockMeta); + switch (BlockType) + { + case E_BLOCK_LEVER: // Treating lever as a torch + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + { + static Vector3i Surroundings [] = { + Vector3i(-1, 0, 0), + Vector3i(1, 0, 0), + Vector3i(0, 0,-1), + Vector3i(0, 0, 1), + }; + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i OtherPos = SourcePos + Surroundings[i]; + if (PowerBlock(OtherPos, a_BlockPos, 0xf)) + { + SpreadStack.push_back(OtherPos); // Changed, so add to stack + } + } + break; + } + + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + { + static Vector3i Surroundings [] = { + Vector3i(0, 0, 0), + Vector3i(0, 1, 0), + }; + Vector3i Direction = GetRepeaterDirection(BlockMeta); + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i pos = SourcePos + Direction + Surroundings[i]; + if (PowerBlock(pos, a_BlockPos, 0xf)) + { + SpreadStack.push_back(pos); + } + } + break; + } + } // switch (BlockType) + } // while (Sources[]) + } // if (!repeater_on) + + // Do a floodfill + while (!SpreadStack.empty()) + { + Vector3i pos = SpreadStack.back(); + SpreadStack.pop_back(); + NIBBLETYPE Meta = m_World.GetBlockMeta(pos); + + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i OtherPos = pos + Surroundings[i]; + if (PowerBlock(OtherPos, pos, Meta - 1)) + { + SpreadStack.push_back(OtherPos); // Changed, so add to stack + } + } + } + + // Only after a redstone area has been completely simulated the redstone entities can react + while (!m_RefreshPistons.empty()) + { + Vector3i pos = m_RefreshPistons.back(); + m_RefreshPistons.pop_back(); + + BLOCKTYPE BlockType = m_World.GetBlock(pos); + switch (BlockType) + { + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + { + if (IsPowered(pos)) + { + cPiston Piston(&m_World); + Piston.ExtendPiston(pos.x, pos.y, pos.z); + } + else + { + cPiston Piston(&m_World); + Piston.RetractPiston(pos.x, pos.y, pos.z); + } + break; + } + } // switch (BlockType) + } // while (m_RefreshPistons[]) + + while (!m_RefreshDropSpensers.empty()) + { + Vector3i pos = m_RefreshDropSpensers.back(); + m_RefreshDropSpensers.pop_back(); + + BLOCKTYPE BlockType = m_World.GetBlock(pos); + if ((BlockType == E_BLOCK_DISPENSER) || (BlockType == E_BLOCK_DROPPER)) + { + class cSetPowerToDropSpenser : + public cDropSpenserCallback + { + bool m_IsPowered; + public: + cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} + + virtual bool Item(cDropSpenserEntity * a_DropSpenser) override + { + a_DropSpenser->SetRedstonePower(m_IsPowered); + return false; + } + } DrSpSP(IsPowered(pos)); + m_World.DoWithDropSpenserAt(pos.x, pos.y, pos.z, DrSpSP); + } + } +} + + + + + +bool cRedstoneSimulator::PowerBlock(const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power) +{ + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); + switch (BlockType) + { + case E_BLOCK_REDSTONE_WIRE: + { + if (BlockMeta < a_Power) + { + m_World.SetBlockMeta(a_BlockPos, a_Power); + return true; + } + break; + } + + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + { + m_RefreshPistons.push_back(a_BlockPos); + break; + } + + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + { + m_RefreshDropSpensers.push_back(a_BlockPos); + break; + } + + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + { + if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) + { + SetRepeater(a_BlockPos, 10, true); + } + break; + } + + case E_BLOCK_REDSTONE_LAMP_OFF: + { + m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_ON, 0); + break; + } + + case E_BLOCK_TNT: + { + m_World.BroadcastSoundEffect("random.fuse", a_BlockPos.x * 8, a_BlockPos.y * 8, a_BlockPos.z * 8, 0.5f, 0.6f); + m_World.SpawnPrimedTNT(a_BlockPos.x + 0.5, a_BlockPos.y + 0.5, a_BlockPos.z + 0.5, 4); // 4 seconds to boom + m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_AIR, 0); + break; + } + + default: + { + if ( + (BlockType != E_BLOCK_AIR) && + (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && + (BlockType != E_BLOCK_REDSTONE_TORCH_OFF) && + (BlockType != E_BLOCK_LEVER) // Treating lever as a torch, for refreshing + ) + { + if (IsPowered(a_BlockPos, true)) + { + m_RefreshTorchesAround.push_back(a_BlockPos); + } + } + break; + } + } // switch (BlockType) + + return false; +} + + + + + +int cRedstoneSimulator::UnPowerBlock(const Vector3i & a_BlockPos, const Vector3i & a_FromBlock) +{ + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if ((a_BlockPos.y < 0) || (a_BlockPos.y >= cChunkDef::Height)) + { + return 0; + } + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); + switch (BlockType) + { + case E_BLOCK_REDSTONE_WIRE: + { + if (BlockMeta > 0) + { + m_World.SetBlockMeta(a_BlockPos, 0); + return 1; + } + break; + } + + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + { + m_RefreshPistons.push_back(a_BlockPos); + break; + } + + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + { + m_RefreshDropSpensers.push_back(a_BlockPos); + break; + } + + case E_BLOCK_REDSTONE_TORCH_ON: + { + return 2; + break; + } + + case E_BLOCK_LEVER: + { + // Check if lever is ON. If it is, report it back as a source + if (cRedstoneSimulator::IsLeverOn(BlockMeta)) + { + return 2; + } + break; + } + + case E_BLOCK_REDSTONE_REPEATER_ON: + { + if ( + IsRepeaterPointingTo(a_BlockPos, BlockMeta, a_FromBlock) || // Repeater is next to wire + IsRepeaterPointingTo(a_BlockPos, BlockMeta, a_FromBlock - Vector3i(0, 1, 0)) // Repeater is below wire + ) + { + return 2; + } + else if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) + { + SetRepeater(a_BlockPos, 10, false); + } + // fall-through: + } + + case E_BLOCK_REDSTONE_REPEATER_OFF: + { + if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) + { + SetRepeater(a_BlockPos, 10, false); + } + break; + } + + case E_BLOCK_REDSTONE_LAMP_ON: + { + m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_OFF, 0); + break; + } + + default: + { + if ( + (BlockType != E_BLOCK_AIR) && + (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && + (BlockType != E_BLOCK_REDSTONE_TORCH_OFF) && + (BlockType != E_BLOCK_LEVER) + ) + { + if (!IsPowered(a_BlockPos, true)) + { + m_RefreshTorchesAround.push_back(a_BlockPos); + } + } + break; + } + } // switch (BlockType) + + return 0; +} + + + + + +// Removes current from all powered redstone wires until it reaches an energy source. +// Also returns all energy sources it encountered +cRedstoneSimulator::BlockList cRedstoneSimulator::RemoveCurrent(const Vector3i & a_BlockPos) +{ + + + std::deque< Vector3i > SpreadStack; + std::deque< Vector3i > FoundSources; + + Vector3i Surroundings[] = { + Vector3i(1, 0, 0), + Vector3i(1, 1, 0), + Vector3i(1,-1, 0), + Vector3i(-1, 0, 0), + Vector3i(-1, 1, 0), + Vector3i(-1,-1, 0), + Vector3i(0, 0, 1), + Vector3i(0, 1, 1), + Vector3i(0,-1, 1), + Vector3i(0, 0,-1), + Vector3i(0, 1,-1), + Vector3i(0,-1,-1), + Vector3i(0,-1, 0), + }; + + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); + switch (BlockType) + { + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + { + // Repeaters only spread to their front front and 0 or 1 block up + static Vector3i Surroundings [] = { + Vector3i(0, 0, 0), + Vector3i(0, 1, 0), + }; + Vector3i Direction = GetRepeaterDirection(BlockMeta); + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i pos = a_BlockPos + Direction + Surroundings[i]; + int RetVal = UnPowerBlock(pos, a_BlockPos); + if (RetVal == 1) + { + // Changed, so add to stack + SpreadStack.push_back(pos); + } + else if (RetVal == 2) + { + FoundSources.push_back(pos); + } + } + break; + } + + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_LEVER: + { + static Vector3i Surroundings [] = { // Torches only spread on the same level + Vector3i(-1, 0, 0), + Vector3i(1, 0, 0), + Vector3i(0, 0,-1), + Vector3i(0, 0, 1), + }; + + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i pos = Vector3i(a_BlockPos) + Surroundings[i]; + int RetVal = UnPowerBlock(pos, a_BlockPos); + if (RetVal == 1) + { + SpreadStack.push_back(pos); // Changed, so add to stack + } + else if (RetVal == 2) + { + FoundSources.push_back(pos); + } + } + break; + } + + default: + { + SpreadStack.push_back(a_BlockPos); + break; + } + } // switch (BlockType) + + + while (!SpreadStack.empty()) + { + Vector3i pos = SpreadStack.back(); + SpreadStack.pop_back(); + + for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + { + Vector3i OtherPos = pos + Surroundings[i]; + int RetVal = UnPowerBlock(OtherPos, pos); + if (RetVal == 1) + { + SpreadStack.push_back(OtherPos); // Changed, so add to stack + } + else if (RetVal == 2) + { + FoundSources.push_back(OtherPos); + } + } + } + + return FoundSources; +} + + + + + +bool cRedstoneSimulator::IsPowering(const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire) +{ + BLOCKTYPE PowerBlock; + NIBBLETYPE PowerMeta; + m_World.GetBlockTypeMeta(a_PowerPos.x, a_PowerPos.y, a_PowerPos.z, PowerBlock, PowerMeta); + + // Filter out powering blocks for a_bOnlyByWire + if ( + !a_bOnlyByWire && ( + (PowerBlock == E_BLOCK_REDSTONE_TORCH_ON) || + (PowerBlock == E_BLOCK_LEVER) + ) + ) + { + return true; + } + + switch (PowerBlock) + { + case E_BLOCK_REDSTONE_REPEATER_ON: + { + // A repeater pointing towards block is regarded as wire + if (IsRepeaterPointingTo(a_PowerPos, PowerMeta, a_BlockPos)) + { + return true; + } + break; + } + + case E_BLOCK_REDSTONE_WIRE: + { + if (PowerMeta > 0) + { + if (GetWireDirection(a_PowerPos) == a_WireDirection) + { + return true; + } + } + break; + } + } // switch (PowerBlock) + + return false; +} + + + + + +bool cRedstoneSimulator::IsPowered(const Vector3i & a_BlockPos, bool a_bOnlyByWire /* = false */) +{ + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); + if ((BlockType == E_BLOCK_REDSTONE_REPEATER_OFF) || (BlockType == E_BLOCK_REDSTONE_REPEATER_ON)) + { + Vector3i Behind = a_BlockPos - GetRepeaterDirection(BlockMeta); + BLOCKTYPE BehindBlock; + NIBBLETYPE BehindMeta; + m_World.GetBlockTypeMeta(Behind.x, Behind.y, Behind.z, BehindBlock, BehindMeta); + switch (BehindBlock) + { + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_LEVER: + { + // _X: TODO: Shouldn't a lever be checked if it is switched on? + return true; + } + case E_BLOCK_REDSTONE_WIRE: + { + return (BehindMeta > 0); + } + case E_BLOCK_REDSTONE_REPEATER_ON: + { + return IsRepeaterPointingTo(Behind, BehindMeta, a_BlockPos); + } + } // switch (BehindBlock) + return false; + } + + if (IsPowering(Vector3i(a_BlockPos.x - 1, a_BlockPos.y, a_BlockPos.z), a_BlockPos, REDSTONE_X_POS, a_bOnlyByWire)) + { + return true; + } + if (IsPowering(Vector3i(a_BlockPos.x + 1, a_BlockPos.y, a_BlockPos.z), a_BlockPos, REDSTONE_X_NEG, a_bOnlyByWire)) + { + return true; + } + if (IsPowering(Vector3i(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z - 1), a_BlockPos, REDSTONE_Z_POS, a_bOnlyByWire)) + { + return true; + } + if (IsPowering(Vector3i(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z + 1), a_BlockPos, REDSTONE_Z_NEG, a_bOnlyByWire)) + { + return true; + } + + // Only wires can power the bottom block + BLOCKTYPE PosYType; + NIBBLETYPE PosYMeta; + m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y + 1, a_BlockPos.z, PosYType, PosYMeta); + if (PosYType == E_BLOCK_REDSTONE_WIRE) + { + return (PosYMeta > 0); + } + + return false; +} + + + + +// Believe me, it works!! TODO: Add repeaters and low/high wires +cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + int Dir = REDSTONE_NONE; + + BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + if ( + (NegX == E_BLOCK_REDSTONE_WIRE) || + (NegX == E_BLOCK_REDSTONE_TORCH_ON) || + (NegX == E_BLOCK_LEVER) + ) + { + Dir |= (REDSTONE_X_POS); + } + + BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + if ( + (PosX == E_BLOCK_REDSTONE_WIRE) || + (PosX == E_BLOCK_REDSTONE_TORCH_ON) || + (PosX == E_BLOCK_LEVER) + ) + { + Dir |= (REDSTONE_X_NEG); + } + + BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + if ( + (NegZ == E_BLOCK_REDSTONE_WIRE) || + (NegZ == E_BLOCK_REDSTONE_TORCH_ON) || + (NegZ == E_BLOCK_LEVER) + ) + { + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_POS; + } + + BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); + if ( + (PosZ == E_BLOCK_REDSTONE_WIRE) || + (PosZ == E_BLOCK_REDSTONE_TORCH_ON) || + (PosZ == E_BLOCK_LEVER) + ) + { + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_NEG; + } + + return (eRedstoneDirection)Dir; +} + + + + + +bool cRedstoneSimulator::IsRepeaterPointingTo(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) +{ + switch (a_MetaData & 0x3) + { + case 0x0: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0, 1))) + { + return true; + } + break; + } + + case 0x1: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(-1, 0, 0))) + { + return true; + } + break; + } + + case 0x2: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0,-1))) + { + return true; + } + break; + } + + case 0x3: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(1, 0, 0))) + { + return true; + } + break; + } + } + return false; +} + + + + + +bool cRedstoneSimulator::IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) +{ + switch (a_MetaData & 0x3) + { + case 0x0: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0,-1))) + { + return true; + } + break; + } + + case 0x1: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(1, 0, 0))) + { + return true; + } + break; + } + + case 0x2: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0, 1))) + { + return true; + } + break; + } + + case 0x3: + { + if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(-1, 0, 0))) + { + return true; + } + break; + } + } + return false; +} + + + + + +NIBBLETYPE cRedstoneSimulator::RepeaterRotationToMetaData(double a_Rotation) +{ + a_Rotation += 90 + 45; // So its not aligned with axis + if (a_Rotation > 360) + { + a_Rotation -= 360; + } + + if ((a_Rotation >= 0) && (a_Rotation < 90)) + { + return 0x1; + } + else if ((a_Rotation >= 180) && (a_Rotation < 270)) + { + return 0x3; + } + else if ((a_Rotation >= 90) && (a_Rotation < 180)) + { + return 0x2; + } + else + { + return 0x0; + } +} + + + + + +Vector3i cRedstoneSimulator::GetRepeaterDirection(NIBBLETYPE a_MetaData) +{ + switch (a_MetaData & 0x3) + { + case 0x0: return Vector3i(0, 0,-1); + case 0x1: return Vector3i(1, 0, 0); + case 0x2: return Vector3i(0, 0, 1); + case 0x3: return Vector3i(-1, 0, 0); + } + return Vector3i(); +} + + + + + +NIBBLETYPE cRedstoneSimulator::LeverDirectionToMetaData(char a_Dir) +{ + // Determine lever direction: + switch (a_Dir) + { + case BLOCK_FACE_TOP: return 0x6; + case BLOCK_FACE_EAST: return 0x1; + case BLOCK_FACE_WEST: return 0x2; + case BLOCK_FACE_SOUTH: return 0x3; + case BLOCK_FACE_NORTH: return 0x4; + case BLOCK_FACE_BOTTOM: return 0x0; + default: return 0x6; + } +} + + + + + +bool cRedstoneSimulator::IsLeverOn(cWorld * a_World, const Vector3i & a_BlockPos) +{ + // Extract the metadata and ask the lower level: + return IsLeverOn(a_World->GetBlockMeta(a_BlockPos)); +} + + + + + +bool cRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) +{ + // Extract the ON bit from metadata and return if true if it is set: + return ((a_BlockMeta & 0x8) == 0x8); +} + + + + + +void cRedstoneSimulator::SetRepeater(const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn) +{ + for (RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end(); ++itr) + { + sRepeaterChange & Change = *itr; + if (Change.Position.Equals(a_Position)) + { + if (Change.bPowerOn && !a_bPowerOn) + { + Change.bPowerOffNextTime = true; + } + if (a_bPowerOn) + { + Change.bPowerOffNextTime = false; + } + Change.bPowerOn |= a_bPowerOn; + return; + } + } + + sRepeaterChange RC; + RC.Position = a_Position; + RC.Ticks = a_Ticks; + RC.bPowerOn = a_bPowerOn; + RC.bPowerOffNextTime = false; + m_SetRepeaters.push_back(RC); +} + + + + -- cgit v1.2.3 From 1d69c80ad38b494f737bde455225259192093c15 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Nov 2013 22:27:08 +0000 Subject: Implemented trapdoors, fixes #43 and #105 Also updated redstone simulator to support it --- src/Simulator/RedstoneSimulator.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 81d4e26f6..ff6005acf 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -169,6 +169,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; + case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_TORCH_OFF: @@ -717,6 +718,22 @@ void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BL +void cRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4); + } + else + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too + } +} + + + + + bool cRedstoneSimulator::AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list -- cgit v1.2.3 From 8d88c8f26fbf82e037bb2ea54612d104e4109faa Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 30 Nov 2013 00:30:49 +0000 Subject: Improved redstone speed and fixed a wire bug The redstone simulator no longer goes through the Powered and LinkedPowered blocks lists for EVERY item in the chunk data, instead, only at every tick. Also, wires powering each other that had the same data value is now fixed. --- src/Simulator/RedstoneSimulator.cpp | 156 +++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 73 deletions(-) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index ff6005acf..9be53ed88 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -76,92 +76,100 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; - for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) + // Check to see if PoweredBlocks have invalid items (source is air or unpowered) + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();) { - BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z); - if (!IsAllowedBlock(BlockType)) + sPoweredBlocks & Change = *itr; + + int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width; + int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width; + + BLOCKTYPE SourceBlockType; + NIBBLETYPE SourceBlockMeta; + if (!a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta)) { - dataitr = ChunkData.erase(dataitr); continue; } - // Check to see if PoweredBlocks have invalid items (source is air or unpowered) - for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();) + if (SourceBlockType != Change.a_SourceBlock) { - sPoweredBlocks & Change = *itr; + itr = m_PoweredBlocks.erase(itr); + LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock)); + } + else if ( + // Changeable sources + ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || + ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || + ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) || + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) + ) + { + itr = m_PoweredBlocks.erase(itr); + LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock)); + } + else + { + itr++; + } + } - int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width; - int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width; + // Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();) + { + sLinkedPoweredBlocks & Change = *itr; - BLOCKTYPE SourceBlockType; - NIBBLETYPE SourceBlockMeta; - a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta); + int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width; + int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width; + int MidRelX = Change.a_MiddlePos.x - a_ChunkX * cChunkDef::Width; + int MidRelZ = Change.a_MiddlePos.z - a_ChunkZ * cChunkDef::Width; - if (SourceBlockType != Change.a_SourceBlock) - { - itr = m_PoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock)); - } - else if ( - // Changeable sources - ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || - ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || - ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) || - (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) - ) - { - itr = m_PoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock)); - } - else - { - itr++; - } + BLOCKTYPE SourceBlockType; + NIBBLETYPE SourceBlockMeta; + BLOCKTYPE MiddleBlockType; + if ( + !a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta) || + !a_Chunk->UnboundedRelGetBlockType(MidRelX, Change.a_MiddlePos.y, MidRelZ, MiddleBlockType) + ) + { + continue; } - // Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed - for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();) + if (SourceBlockType != Change.a_SourceBlock) { - sLinkedPoweredBlocks & Change = *itr; - - int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width; - int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width; - int MidRelX = Change.a_MiddlePos.x - a_ChunkX * cChunkDef::Width; - int MidRelZ = Change.a_MiddlePos.z - a_ChunkZ * cChunkDef::Width; - - BLOCKTYPE SourceBlockType; - NIBBLETYPE SourceBlockMeta; - BLOCKTYPE MiddleBlockType; - a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta); - a_Chunk->UnboundedRelGetBlockType(MidRelX, Change.a_MiddlePos.y, MidRelZ, MiddleBlockType); - - if (SourceBlockType != Change.a_SourceBlock) - { - itr = m_LinkedPoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock)); - } - else if (MiddleBlockType != Change.a_MiddleBlock) - { - itr = m_LinkedPoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(Change.a_SourceBlock)); - } - else if ( - // Things that can send power through a block but which depends on meta - ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || - ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || - (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) - ) - { - itr = m_LinkedPoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock)); - } - else - { - itr++; - } + itr = m_LinkedPoweredBlocks.erase(itr); + LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock)); + } + else if (MiddleBlockType != Change.a_MiddleBlock) + { + itr = m_LinkedPoweredBlocks.erase(itr); + LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(Change.a_SourceBlock)); + } + else if ( + // Things that can send power through a block but which depends on meta + ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || + ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) + ) + { + itr = m_LinkedPoweredBlocks.erase(itr); + LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock)); + } + else + { + itr++; + } + } + + for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) + { + BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z); + if (!IsAllowedBlock(BlockType)) + { + dataitr = ChunkData.erase(dataitr); + continue; } - // PoweredBlock list was fine, now to the actual handling + // PoweredBlock and LinkedPoweredBlock list was fine, now to the actual handling int a_X = BaseX + dataitr->x; int a_Z = BaseZ + dataitr->z; switch (BlockType) @@ -407,7 +415,9 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking { - if (SurroundMeta > MyMeta) // Does surrounding wire have a higher power level than self? + // Does surrounding wire have a higher power level than self? + // >= to fix a bug where wires bordering each other with the same power level will appear (in terms of meta) to power each other, when they aren't actually in the powered list + if (SurroundMeta >= MyMeta) { m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, SurroundMeta - 1); } -- cgit v1.2.3 From 455686e3ade61999d377965e02315603959ae2a4 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 30 Nov 2013 12:11:39 +0000 Subject: Pistons no longer accept power through front face This fixes #60. --- src/Simulator/RedstoneSimulator.cpp | 97 +++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 3 deletions(-) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 9be53ed88..c4da2db3a 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -566,7 +566,7 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int void cRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ) { cPiston Piston(&m_World); - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (IsPistonPowered(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) { Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ); } @@ -774,7 +774,8 @@ bool cRedstoneSimulator::AreCoordsPowered(int a_BlockX, int a_BlockY, int a_Bloc bool cRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) { - // Check through powered blocks list + // Repeaters cannot be powered by any face except their back; verify that this is true for a source + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) { sPoweredBlocks & Change = *itr; @@ -807,7 +808,6 @@ bool cRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_Blo } } - // Check linked powered list, 'middle' blocks for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) { sLinkedPoweredBlocks & Change = *itr; @@ -844,6 +844,97 @@ bool cRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_Blo +bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) +{ + // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement + + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) + { + sPoweredBlocks & Change = *itr; + + if (!Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + + switch (a_Meta) // Pistons' metas are the directions they face; the source cannot be there + { + case BLOCK_FACE_YM: + { + if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY - 1, a_BlockZ))) { return true; } + break; + } + case BLOCK_FACE_YP: + { + if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY + 1, a_BlockZ))) { return true; } + break; + } + case BLOCK_FACE_ZM: + { + if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + break; + } + case BLOCK_FACE_ZP: + { + if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + break; + } + case BLOCK_FACE_XM: + { + if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + break; + } + case BLOCK_FACE_XP: + { + if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + break; + } + } + } + + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + { + sLinkedPoweredBlocks & Change = *itr; + + if (!Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + + switch (a_Meta) + { + case BLOCK_FACE_YM: + { + if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY - 1, a_BlockZ))) { return true; } + break; + } + case BLOCK_FACE_YP: + { + if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY + 1, a_BlockZ))) { return true; } + break; + } + case BLOCK_FACE_ZM: + { + if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + break; + } + case BLOCK_FACE_ZP: + { + if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + break; + } + case BLOCK_FACE_XM: + { + if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + break; + } + case BLOCK_FACE_XP: + { + if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + break; + } + } + } + return false; // Source was in front of the piston's front face +} + + + + void cRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType) { -- cgit v1.2.3 From d12106ee97dcc3d414792f695c0644724ac80f87 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 30 Nov 2013 13:41:40 +0000 Subject: Improved piston direction checking Now uses AddFaceDirection, as suggested by xoft. --- src/Simulator/RedstoneSimulator.cpp | 70 +++++-------------------------------- 1 file changed, 8 insertions(+), 62 deletions(-) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index c4da2db3a..b6e1566ef 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -854,38 +854,11 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block if (!Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - switch (a_Meta) // Pistons' metas are the directions they face; the source cannot be there + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Meta); // Piston meta is based on what direction they face, so we can do this + + if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - case BLOCK_FACE_YM: - { - if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY - 1, a_BlockZ))) { return true; } - break; - } - case BLOCK_FACE_YP: - { - if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY + 1, a_BlockZ))) { return true; } - break; - } - case BLOCK_FACE_ZM: - { - if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } - break; - } - case BLOCK_FACE_ZP: - { - if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } - break; - } - case BLOCK_FACE_XM: - { - if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } - break; - } - case BLOCK_FACE_XP: - { - if (!Change.a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } - break; - } + return true; } } @@ -895,38 +868,11 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block if (!Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - switch (a_Meta) + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Meta); + + if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - case BLOCK_FACE_YM: - { - if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY - 1, a_BlockZ))) { return true; } - break; - } - case BLOCK_FACE_YP: - { - if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY + 1, a_BlockZ))) { return true; } - break; - } - case BLOCK_FACE_ZM: - { - if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } - break; - } - case BLOCK_FACE_ZP: - { - if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } - break; - } - case BLOCK_FACE_XM: - { - if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } - break; - } - case BLOCK_FACE_XP: - { - if (!Change.a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } - break; - } + return true; } } return false; // Source was in front of the piston's front face -- cgit v1.2.3 From 363db1bdc46933fc30f99e23736ae0d2f3c90211 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 30 Nov 2013 13:52:11 +0000 Subject: Removed redstone duplicate power checking There was no need for it, and it introduced some bugs. --- src/Simulator/RedstoneSimulator.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index b6e1566ef..d9a9372e0 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -1150,7 +1150,6 @@ void cRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_B void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock) { if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) { return; } // Don't set air, fixes some bugs (wires powering themselves) - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { return; } // Check for duplicates sPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); @@ -1171,7 +1170,6 @@ void cRedstoneSimulator::SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a ) { if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) { return; } // Don't set air, fixes some bugs (wires powering themselves) - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { return; } // Check for duplicates if (!IsViableMiddleBlock(m_World.GetBlock(a_MiddleX, a_MiddleY, a_MiddleZ))) { return; } // See if middle block is viable sLinkedPoweredBlocks RC; -- cgit v1.2.3 From fad43f0c405450cba98b995fbaebec7064d2aff2 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 30 Nov 2013 15:07:21 +0000 Subject: Fixed pistons extending They didn't when a source was in front, but now they do! Yay! --- src/Simulator/RedstoneSimulator.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index d9a9372e0..c93741a0e 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -848,6 +848,8 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block { // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement + int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ; + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) { sPoweredBlocks & Change = *itr; @@ -860,6 +862,10 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block { return true; } + + a_BlockX = OldX; + a_BlockY = OldY; + a_BlockZ = OldZ; } for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) @@ -874,6 +880,10 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block { return true; } + + a_BlockX = OldX; + a_BlockY = OldY; + a_BlockZ = OldZ; } return false; // Source was in front of the piston's front face } -- cgit v1.2.3 From 3dfd051fcb44020e4accc9bcb6b5ee28c06d2902 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 1 Dec 2013 13:58:04 +0100 Subject: Fixed linux compile errors and formatting in RedstoneSimulator.cpp --- src/Simulator/RedstoneSimulator.cpp | 40 ++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index c93741a0e..9fdbd1151 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -94,7 +94,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c if (SourceBlockType != Change.a_SourceBlock) { itr = m_PoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock)); + LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock).c_str()); } else if ( // Changeable sources @@ -105,7 +105,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c ) { itr = m_PoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock)); + LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock).c_str()); } else { @@ -137,12 +137,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c if (SourceBlockType != Change.a_SourceBlock) { itr = m_LinkedPoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock)); + LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock).c_str()); } else if (MiddleBlockType != Change.a_MiddleBlock) { itr = m_LinkedPoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(Change.a_SourceBlock)); + LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(Change.a_SourceBlock).c_str()); } else if ( // Things that can send power through a block but which depends on meta @@ -152,7 +152,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c ) { itr = m_LinkedPoweredBlocks.erase(itr); - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock)); + LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock).c_str()); } else { @@ -267,10 +267,10 @@ void cRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_B } // Torch still on, make all 4(X, Z) + 1(Y) sides powered - for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z); - if (i < ARRAYCOUNT(gCrossCoords) - 1) // Sides of torch, not top (top is last) + if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last) { if ( ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc. @@ -403,7 +403,7 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); int TimesMetaSmaller = 0, TimesFoundAWire = 0; - for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power + for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power { BLOCKTYPE SurroundType; NIBBLETYPE SurroundMeta; @@ -1146,7 +1146,7 @@ void cRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_B { 0,-1, 0 } }; - for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions + for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions { SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock); } @@ -1159,7 +1159,11 @@ void cRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_B void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock) { - if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) { return; } // Don't set air, fixes some bugs (wires powering themselves) + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + // Don't set air, fixes some bugs (wires powering themselves) + return; + } sPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); @@ -1173,14 +1177,22 @@ void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_Block -void cRedstoneSimulator::SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, +void cRedstoneSimulator::SetBlockLinkedPowered( + int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock - ) +) { - if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) { return; } // Don't set air, fixes some bugs (wires powering themselves) - if (!IsViableMiddleBlock(m_World.GetBlock(a_MiddleX, a_MiddleY, a_MiddleZ))) { return; } // See if middle block is viable + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + // Don't set air, fixes some bugs (wires powering themselves) + return; + } + if (!IsViableMiddleBlock(m_World.GetBlock(a_MiddleX, a_MiddleY, a_MiddleZ))) + { + return; + } sLinkedPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); -- cgit v1.2.3 From 126577214acb1f3f1eb5c99062ddbed3cf1f3756 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 6 Dec 2013 20:33:48 +0000 Subject: Re-implemented redstone duplicate checking --- src/Simulator/RedstoneSimulator.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 9fdbd1151..fef3e8b21 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -1165,6 +1165,20 @@ void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_Block return; } + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list + { + sPoweredBlocks & Change = *itr; + + if ( + Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && + Change.a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) + ) + { + // Check for duplicates + return; + } + } + sPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); @@ -1194,6 +1208,21 @@ void cRedstoneSimulator::SetBlockLinkedPowered( return; } + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list + { + sLinkedPoweredBlocks & Change = *itr; + + if ( + Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && + Change.a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) && + Change.a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) + ) + { + // Check for duplicates + return; + } + } + sLinkedPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); -- cgit v1.2.3 From 1932cc38a1fba31a61be2f1a5d17ced46d5915ad Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 7 Dec 2013 14:41:58 +0000 Subject: Fixed trapdoors not toggling The redstone simulator kept on resetting them. --- src/Simulator/RedstoneSimulator.cpp | 106 ++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 16 deletions(-) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index fef3e8b21..771be6ac1 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -160,6 +160,29 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c } } + for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end();) + { + sSimulatedPlayerToggleableList & Change = *itr; + + int RelX = Change.a_BlockPos.x - a_ChunkX * cChunkDef::Width; + int RelZ = Change.a_BlockPos.z - a_ChunkZ * cChunkDef::Width; + + BLOCKTYPE SourceBlockType; + if (!a_Chunk->UnboundedRelGetBlockType(RelX, Change.a_BlockPos.y, RelZ, SourceBlockType)) + { + continue; + } + else if (!IsAllowedBlock(SourceBlockType)) + { + LOGD("cRedstoneSimulator: Erased block %s from toggleable simulated list due to power state change", ItemToFullString(SourceBlockType).c_str()); + itr = m_SimulatedPlayerToggleableBlocks.erase(itr); + } + else + { + ++itr; + } + } + for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) { BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z); @@ -314,7 +337,6 @@ void cRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_B // Block torch on not powered, can be turned on again! m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); } - return; } @@ -325,7 +347,6 @@ void cRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_B { SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); // Set self as powered - return; } @@ -345,7 +366,6 @@ void cRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_B SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER); } - return; } @@ -497,7 +517,6 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl } } } - return; } @@ -556,7 +575,6 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); } } - return; } @@ -574,7 +592,6 @@ void cRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ) { Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ); } - return; } @@ -598,7 +615,6 @@ void cRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_Blo } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP); - return; } @@ -621,7 +637,6 @@ void cRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_Bl m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); } } - return; } @@ -636,7 +651,6 @@ void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ) m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); } - return; } @@ -689,7 +703,6 @@ void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) } } } - return; } @@ -732,11 +745,19 @@ void cRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ { if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4); + if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4); + SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + } } else { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too + if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too + SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + } } } @@ -892,6 +913,31 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block +bool cRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered) +{ + for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr) + { + sSimulatedPlayerToggleableList & Change = *itr; + + if (Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + { + if (Change.WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current? + { + return false; // It was, coordinates are no longer simulated + } + else + { + return true; // It wasn't, don't resimulate block, and allow players to toggle + } + } + } + return false; // Block wasn't even in the list, not simulated +} + + + + + void cRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType) { switch (a_Direction) @@ -1124,7 +1170,6 @@ void cRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, i break; } } - return; } @@ -1150,7 +1195,6 @@ void cRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_B { SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock); } - return; } @@ -1184,7 +1228,6 @@ void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_Block RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); RC.a_SourceBlock = a_SourceBlock; m_PoweredBlocks.push_back(RC); - return; } @@ -1230,7 +1273,38 @@ void cRedstoneSimulator::SetBlockLinkedPowered( RC.a_SourceBlock = a_SourceBlock; RC.a_MiddleBlock = a_MiddleBlock; m_LinkedPoweredBlocks.push_back(RC); - return; +} + + + + + +void cRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered) +{ + for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr) + { + sSimulatedPlayerToggleableList & Change = *itr; + + if (Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + { + if (Change.WasLastStatePowered != WasLastStatePowered) + { + // If power states different, erase the old listing in preparation to add new one + m_SimulatedPlayerToggleableBlocks.erase(itr); + break; + } + else + { + // If states the same, just ignore + return; + } + } + } + + sSimulatedPlayerToggleableList RC; + RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.WasLastStatePowered = WasLastStatePowered; + m_SimulatedPlayerToggleableBlocks.push_back(RC); } -- cgit v1.2.3 From a61082ffee9c8182d053b4b335bd80bced376606 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 7 Dec 2013 14:55:19 +0000 Subject: Changed some FastSetBlocks to SetBlock Should fix some duplication glitches. --- src/Simulator/RedstoneSimulator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Simulator/RedstoneSimulator.cpp') diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 771be6ac1..63e4f04a8 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -627,14 +627,14 @@ void cRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_Bl { if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); + m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); } } else { if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); + m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); } } } @@ -649,7 +649,7 @@ void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ) { m_World.BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom - m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); } } -- cgit v1.2.3