diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | MCServer/.gitignore | 1 | ||||
-rw-r--r-- | SetFlags.cmake | 2 | ||||
-rw-r--r-- | src/BoundingBox.cpp | 20 | ||||
-rw-r--r-- | src/Chunk.h | 14 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 22 | ||||
-rw-r--r-- | src/CompositeChat.cpp | 222 | ||||
-rw-r--r-- | src/CompositeChat.h | 11 | ||||
-rw-r--r-- | src/Entities/Player.h | 3 | ||||
-rw-r--r-- | src/Items/ItemLighter.h | 2 | ||||
-rw-r--r-- | src/Mobs/Creeper.cpp | 2 | ||||
-rw-r--r-- | src/Mobs/Wolf.cpp | 45 | ||||
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator.cpp | 205 | ||||
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator.h | 38 |
14 files changed, 446 insertions, 146 deletions
diff --git a/.gitignore b/.gitignore index 007b21519..c8ad93a80 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,9 @@ cloc.xsl *.*~ *~ *.orig +## Eclipse +.cproject +.project # world inside source ChunkWorx.ini @@ -57,7 +60,7 @@ install_mainfest.txt src/MCServer lib/tolua++/tolua src/Bindings/Bindings.* -src/Bindings/BindingsDependecies.txt +src/Bindings/BindingDependecies.txt MCServer.dir/ #win32 cmake stuff diff --git a/MCServer/.gitignore b/MCServer/.gitignore index e3aebbf92..0fd04ef59 100644 --- a/MCServer/.gitignore +++ b/MCServer/.gitignore @@ -4,6 +4,7 @@ *.lib *.ini MCServer +MCServer_debug CommLogs/ logs players diff --git a/SetFlags.cmake b/SetFlags.cmake index 162560c90..ded57e6d7 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -183,7 +183,7 @@ macro(set_exe_flags) string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") - add_flags_cxx("-Wall") + add_flags_cxx("-Wall -Wextra") endif() endmacro() diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp index 47b135688..aab51c539 100644 --- a/src/BoundingBox.cpp +++ b/src/BoundingBox.cpp @@ -12,25 +12,25 @@ #if SELF_TEST -/// A simple self-test that is executed on program start, used to verify bbox functionality -class SelfTest +/** A simple self-test that is executed on program start, used to verify bbox functionality */ +static class SelfTest_BoundingBox { public: - SelfTest(void) + SelfTest_BoundingBox(void) { Vector3d Min(1, 1, 1); Vector3d Max(2, 2, 2); Vector3d LineDefs[] = { - Vector3d(1.5, 4, 1.5), Vector3d(1.5, 3, 1.5), // Should intersect at 2, face 1 (YP) + Vector3d(1.5, 4, 1.5), Vector3d(1.5, 3, 1.5), // Should intersect at 2, face 1 (YP) Vector3d(1.5, 0, 1.5), Vector3d(1.5, 4, 1.5), // Should intersect at 0.25, face 0 (YM) Vector3d(0, 0, 0), Vector3d(2, 2, 2), // Should intersect at 0.5, face 0, 3 or 5 (anyM) Vector3d(0.999, 0, 1.5), Vector3d(0.999, 4, 1.5), // Should not intersect Vector3d(1.999, 0, 1.5), Vector3d(1.999, 4, 1.5), // Should intersect at 0.25, face 0 (YM) Vector3d(2.001, 0, 1.5), Vector3d(2.001, 4, 1.5), // Should not intersect } ; - bool Results[] = {true,true,true,false,true,false}; - double LineCoeffs[] = {2,0.25,0.5,0,0.25,0}; + bool Results[] = {true, true, true, false, true, false}; + double LineCoeffs[] = {2, 0.25, 0.5, 0, 0.25, 0}; for (size_t i = 0; i < ARRAYCOUNT(LineDefs) / 2; i++) { @@ -41,7 +41,7 @@ public: bool res = cBoundingBox::CalcLineIntersection(Min, Max, Line1, Line2, LineCoeff, Face); if (res != Results[i]) { - fprintf(stderr,"LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n", + fprintf(stderr, "LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n", Line1.x, Line1.y, Line1.z, Line2.x, Line2.y, Line2.z, res ? 1 : 0, LineCoeff, Face @@ -52,7 +52,7 @@ public: { if (LineCoeff != LineCoeffs[i]) { - fprintf(stderr,"LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n", + fprintf(stderr, "LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n", Line1.x, Line1.y, Line1.z, Line2.x, Line2.y, Line2.z, res ? 1 : 0, LineCoeff, Face @@ -61,9 +61,9 @@ public: } } } // for i - LineDefs[] - fprintf(stderr,"BoundingBox selftest complete."); + fprintf(stderr, "BoundingBox selftest complete.\n"); } -} Test; +} gTest; #endif diff --git a/src/Chunk.h b/src/Chunk.h index 93eba217e..696690068 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -343,12 +343,17 @@ public: NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const; - // Simulator data: + // Per-chunk simulator data: cFireSimulatorChunkData & GetFireSimulatorData (void) { return m_FireSimulatorData; } cFluidSimulatorData * GetWaterSimulatorData(void) { return m_WaterSimulatorData; } cFluidSimulatorData * GetLavaSimulatorData (void) { return m_LavaSimulatorData; } cSandSimulatorChunkData & GetSandSimulatorData (void) { return m_SandSimulatorData; } - cRedstoneSimulatorChunkData & GetRedstoneSimulatorData(void) { return m_RedstoneSimulatorData; } + + cRedstoneSimulatorChunkData * GetRedstoneSimulatorData(void) { return &m_RedstoneSimulatorData; } + cIncrementalRedstoneSimulator::PoweredBlocksList * GetRedstoneSimulatorPoweredBlocksList(void) { return &m_RedstoneSimulatorPoweredBlocksList; } + cIncrementalRedstoneSimulator::LinkedBlocksList * GetRedstoneSimulatorLinkedBlocksList(void) { return &m_RedstoneSimulatorLinkedBlocksList; }; + cIncrementalRedstoneSimulator::SimulatedPlayerToggleableList * GetRedstoneSimulatorSimulatedPlayerToggleableList(void) { return &m_RedstoneSimulatorSimulatedPlayerToggleableList; }; + cIncrementalRedstoneSimulator::RepeatersDelayList * GetRedstoneSimulatorRepeatersDelayList(void) { return &m_RedstoneSimulatorRepeatersDelayList; }; cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } @@ -419,7 +424,12 @@ private: cFluidSimulatorData * m_WaterSimulatorData; cFluidSimulatorData * m_LavaSimulatorData; cSandSimulatorChunkData m_SandSimulatorData; + cRedstoneSimulatorChunkData m_RedstoneSimulatorData; + cIncrementalRedstoneSimulator::PoweredBlocksList m_RedstoneSimulatorPoweredBlocksList; + cIncrementalRedstoneSimulator::LinkedBlocksList m_RedstoneSimulatorLinkedBlocksList; + cIncrementalRedstoneSimulator::SimulatedPlayerToggleableList m_RedstoneSimulatorSimulatedPlayerToggleableList; + cIncrementalRedstoneSimulator::RepeatersDelayList m_RedstoneSimulatorRepeatersDelayList; // pick up a random block of this chunk diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index b46bcfd47..c91a0c01b 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1089,14 +1089,20 @@ void cClientHandle::HandleChat(const AString & a_Message) return; } - // Not a command, broadcast as a simple message: - AString Msg; - Printf(Msg, "%s<%s>%s %s", - m_Player->GetColor().c_str(), - m_Player->GetName().c_str(), - cChatColor::White.c_str(), - Message.c_str() - ); + // Not a command, broadcast as a message: + cCompositeChat Msg; + AString Color = m_Player->GetColor(); + if (Color.length() == 3) + { + Color = AString("@") + Color[2]; + } + else + { + Color.empty(); + } + Msg.AddTextPart(AString("<") + m_Player->GetName() + "> ", Color); + Msg.ParseText(a_Message); + Msg.UnderlineUrls(); m_Player->GetWorld()->BroadcastChat(Msg); } diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index 16ae58f56..3eec35657 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -10,6 +10,96 @@ +#if SELF_TEST + +/** A simple self-test that verifies that the composite chat parser is working properly. */ +class SelfTest_CompositeChat +{ +public: + SelfTest_CompositeChat(void) + { + fprintf(stderr, "cCompositeChat self test...\n"); + TestParser1(); + TestParser2(); + TestParser3(); + TestParser4(); + TestParser5(); + fprintf(stderr, "cCompositeChat self test finished.\n"); + } + + void TestParser1(void) + { + cCompositeChat Msg; + Msg.ParseText("Testing @2color codes and http://links parser"); + const cCompositeChat::cParts & Parts = Msg.GetParts(); + assert(Parts.size() == 4); + assert(Parts[0]->m_PartType == cCompositeChat::ptText); + assert(Parts[1]->m_PartType == cCompositeChat::ptText); + assert(Parts[2]->m_PartType == cCompositeChat::ptUrl); + assert(Parts[3]->m_PartType == cCompositeChat::ptText); + assert(Parts[0]->m_Style == ""); + assert(Parts[1]->m_Style == "@2"); + assert(Parts[2]->m_Style == "@2"); + assert(Parts[3]->m_Style == "@2"); + } + + void TestParser2(void) + { + cCompositeChat Msg; + Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling"); + const cCompositeChat::cParts & Parts = Msg.GetParts(); + assert(Parts.size() == 4); + assert(Parts[0]->m_PartType == cCompositeChat::ptText); + assert(Parts[1]->m_PartType == cCompositeChat::ptText); + assert(Parts[2]->m_PartType == cCompositeChat::ptUrl); + assert(Parts[3]->m_PartType == cCompositeChat::ptText); + assert(Parts[0]->m_Style == "@3"); + assert(Parts[1]->m_Style == "@5"); + assert(Parts[2]->m_Style == "@5"); + assert(Parts[3]->m_Style == "@5"); + } + + void TestParser3(void) + { + cCompositeChat Msg; + Msg.ParseText("http://links.starting the text"); + const cCompositeChat::cParts & Parts = Msg.GetParts(); + assert(Parts.size() == 2); + assert(Parts[0]->m_PartType == cCompositeChat::ptUrl); + assert(Parts[1]->m_PartType == cCompositeChat::ptText); + assert(Parts[0]->m_Style == ""); + assert(Parts[1]->m_Style == ""); + } + + void TestParser4(void) + { + cCompositeChat Msg; + Msg.ParseText("links finishing the text: http://some.server"); + const cCompositeChat::cParts & Parts = Msg.GetParts(); + assert(Parts.size() == 2); + assert(Parts[0]->m_PartType == cCompositeChat::ptText); + assert(Parts[1]->m_PartType == cCompositeChat::ptUrl); + assert(Parts[0]->m_Style == ""); + assert(Parts[1]->m_Style == ""); + } + + void TestParser5(void) + { + cCompositeChat Msg; + Msg.ParseText("http://only.links"); + const cCompositeChat::cParts & Parts = Msg.GetParts(); + assert(Parts.size() == 1); + assert(Parts[0]->m_PartType == cCompositeChat::ptUrl); + assert(Parts[0]->m_Style == ""); + } + +} gTest; +#endif // SELF_TEST + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cCompositeChat: @@ -101,7 +191,99 @@ void cCompositeChat::AddSuggestCommandPart(const AString & a_Text, const AString void cCompositeChat::ParseText(const AString & a_ParseText) { - // TODO + size_t len = a_ParseText.length(); + size_t first = 0; // First character of the currently parsed block + AString CurrentStyle; + AString CurrentText; + for (size_t i = 0; i < len; i++) + { + switch (a_ParseText[i]) + { + case '@': + { + // Color code + i++; + if (i >= len) + { + // Not enough following text + break; + } + if (a_ParseText[i] == '@') + { + // "@@" escape, just put a "@" into the current text and keep parsing as text + if (i > first + 1) + { + CurrentText.append(a_ParseText.c_str() + first, i - first - 1); + } + first = i + 1; + continue; + } + else + { + // True color code. Create a part for the CurrentText and start parsing anew: + if (i >= first) + { + CurrentText.append(a_ParseText.c_str() + first, i - first - 1); + first = i + 1; + } + if (!CurrentText.empty()) + { + m_Parts.push_back(new cTextPart(CurrentText, CurrentStyle)); + CurrentText.clear(); + } + AddStyle(CurrentStyle, a_ParseText.substr(i - 1, 2)); + } + break; + } + + case ':': + { + const char * LinkPrefixes[] = + { + "http", + "https" + }; + for (size_t Prefix = 0; Prefix < ARRAYCOUNT(LinkPrefixes); Prefix++) + { + size_t PrefixLen = strlen(LinkPrefixes[Prefix]); + if ( + (i >= first + PrefixLen) && // There is enough space in front of the colon for the prefix + (strncmp(a_ParseText.c_str() + i - PrefixLen, LinkPrefixes[Prefix], PrefixLen) == 0) // the prefix matches + ) + { + // Add everything before this as a text part: + if (i > first + PrefixLen) + { + CurrentText.append(a_ParseText.c_str() + first, i - first - PrefixLen); + first = i - PrefixLen; + } + if (!CurrentText.empty()) + { + AddTextPart(CurrentText, CurrentStyle); + CurrentText.clear(); + } + + // Go till the last non-whitespace char in the text: + for (; i < len; i++) + { + if (isspace(a_ParseText[i])) + { + break; + } + } + AddUrlPart(a_ParseText.substr(first, i - first), a_ParseText.substr(first, i - first), CurrentStyle); + first = i; + break; + } + } // for Prefix - LinkPrefix[] + break; + } // case ':' + } // switch (a_ParseText[i]) + } // for i - a_ParseText[] + if (first < len) + { + AddTextPart(a_ParseText.substr(first, len - first), CurrentStyle); + } } @@ -117,6 +299,44 @@ void cCompositeChat::SetMessageType(eMessageType a_MessageType) +void cCompositeChat::UnderlineUrls(void) +{ + for (cParts::iterator itr = m_Parts.begin(), end = m_Parts.end(); itr != end; ++itr) + { + if ((*itr)->m_PartType == ptUrl) + { + (*itr)->m_Style.append("u"); + } + } // for itr - m_Parts[] +} + + + + + +void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle) +{ + if (a_AddStyle.empty()) + { + return; + } + if (a_AddStyle[0] == '@') + { + size_t idx = a_Style.find('@'); + if ((idx != AString::npos) && (idx != a_Style.length())) + { + a_Style.erase(idx, 2); + } + a_Style.append(a_AddStyle); + return; + } + a_Style.append(a_AddStyle); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cCompositeChat::cBasePart: diff --git a/src/CompositeChat.h b/src/CompositeChat.h index e220f6345..51600da4f 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -48,6 +48,9 @@ public: AString m_Style; cBasePart(ePartType a_PartType, const AString & a_Text, const AString & a_Style = ""); + + // Force a virtual destructor in descendants + virtual ~cBasePart() {} } ; class cTextPart : @@ -155,6 +158,9 @@ public: /** Returns the message type set previously by SetMessageType(). */ eMessageType GetMessageType(void) const { return m_MessageType; } + /** Adds the "underline" style to each part that is an URL. */ + void UnderlineUrls(void); + // tolua_end const cParts & GetParts(void) const { return m_Parts; } @@ -165,6 +171,11 @@ protected: /** The message type, as indicated by prefixes. */ eMessageType m_MessageType; + + + /** Adds a_AddStyle to a_Style; overwrites the existing style if appropriate. + If the style already contains something that a_AddStyle overrides, it is erased first. */ + void AddStyle(AString & a_Style, const AString & a_AddStyle); } ; // tolua_export diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 53e4b56db..a795bb9eb 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -226,7 +226,8 @@ public: // tolua_begin - /// Returns the full color code to use for this player, based on their primary group or set in m_Color + /** Returns the full color code to use for this player, based on their primary group or set in m_Color. + The returned value includes the cChatColor::Delimiter. */ AString GetColor(void) const; /** tosses the item in the selected hotbar slot */ diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h index 6681a08d4..cc7daeb08 100644 --- a/src/Items/ItemLighter.h +++ b/src/Items/ItemLighter.h @@ -33,7 +33,7 @@ public: case E_BLOCK_TNT: { // Activate the TNT: - a_World->BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); + a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0); break; diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp index 2e1ece865..ff0abfdca 100644 --- a/src/Mobs/Creeper.cpp +++ b/src/Mobs/Creeper.cpp @@ -79,7 +79,7 @@ void cCreeper::Attack(float a_Dt) if (!m_bIsBlowing) { - m_World->BroadcastSoundEffect("random.fuse", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); m_bIsBlowing = true; m_World->BroadcastEntityMetadata(*this); } diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index ff324d073..2736c3dd1 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -124,12 +124,6 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); } - - // The wolf is sitting so don't move him at all. - if (IsSitting()) - { - m_bMovingToDestination = false; - } cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance); if (a_Closest_Player != NULL) @@ -148,18 +142,15 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk) SetIsBegging(true); m_World->BroadcastEntityMetadata(*this); } + + m_FinalDestination = a_Closest_Player->GetPosition(); // So that we will look at a player holding food + // Don't move to the player if the wolf is sitting. - if (IsSitting()) - { - m_bMovingToDestination = false; - } - else + if (!IsSitting()) { - m_bMovingToDestination = true; + MoveToPosition(a_Closest_Player->GetPosition()); } - Vector3d PlayerPos = a_Closest_Player->GetPosition(); - PlayerPos.y++; - m_FinalDestination = PlayerPos; + break; } default: @@ -173,10 +164,14 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk) } } - if (IsTame()) + if (IsTame() && !IsSitting()) { TickFollowPlayer(); } + else if (IsSitting()) + { + m_bMovingToDestination = false; + } } @@ -196,29 +191,19 @@ void cWolf::TickFollowPlayer() public: Vector3d OwnerPos; } Callback; + if (m_World->DoWithPlayer(m_OwnerName, Callback)) { // The player is present in the world, follow him: double Distance = (Callback.OwnerPos - GetPosition()).Length(); if (Distance > 30) { - if (!IsSitting()) - { - Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z); - TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z); - } + Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z); + TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z); } else { - m_FinalDestination = Callback.OwnerPos; - if (IsSitting()) - { - m_bMovingToDestination = false; - } - else - { - m_bMovingToDestination = true; - } + MoveToPosition(Callback.OwnerPos); } } } diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 985fdee27..60dabaf84 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -8,7 +8,6 @@ #include "../Entities/TNTEntity.h" #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" -#include "../Blocks/BlockFenceGate.h" #include "../Piston.h" @@ -32,7 +31,7 @@ cIncrementalRedstoneSimulator::~cIncrementalRedstoneSimulator() -void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk) { if ((a_Chunk == NULL) || !a_Chunk->IsValid()) { @@ -43,17 +42,33 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - + // We may be called with coordinates in a chunk that is not the first chunk parameter + // In that case, the actual chunk (which the coordinates are in), will be passed as the second parameter + // Use that Chunk pointer to get a relative position + + int RelX = 0; + int RelZ = 0; BLOCKTYPE Block; NIBBLETYPE Meta; - a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + + if (a_OtherChunk != NULL) + { + RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; + RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width; + a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + } + else + { + RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; + RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; + a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + } // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid // Checking only when a block is changed, as opposed to every tick, also improves performance - for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) + PoweredBlocksList * PoweredBlocks = a_Chunk->GetRedstoneSimulatorPoweredBlocksList(); + for (PoweredBlocksList::iterator itr = PoweredBlocks->begin(); itr != PoweredBlocks->end(); ++itr) { if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -63,7 +78,7 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B if (!IsPotentialSource(Block)) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - m_PoweredBlocks.erase(itr); + PoweredBlocks->erase(itr); break; } else if ( @@ -76,7 +91,7 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B ) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - m_PoweredBlocks.erase(itr); + PoweredBlocks->erase(itr); break; } else if (Block == E_BLOCK_DAYLIGHT_SENSOR) @@ -94,22 +109,24 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness(); { LOGD("cIncrementalRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level"); - m_PoweredBlocks.erase(itr); + PoweredBlocks->erase(itr); break; } } } } - for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + LinkedBlocksList * LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList(); + // We loop through all values (insteading of breaking out at the first) to make sure everything is gone, as there can be multiple SourceBlock entries for one AddBlock coordinate + for (LinkedBlocksList::iterator itr = LinkedPoweredBlocks->begin(); itr != LinkedPoweredBlocks->end();) { if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { if (!IsPotentialSource(Block)) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - m_LinkedPoweredBlocks.erase(itr); - break; + itr = LinkedPoweredBlocks->erase(itr); + continue; } else if ( // Things that can send power through a block but which depends on meta @@ -119,8 +136,8 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B ) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - m_LinkedPoweredBlocks.erase(itr); - break; + itr = LinkedPoweredBlocks->erase(itr); + continue; } } else if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) @@ -128,13 +145,15 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B if (!IsViableMiddleBlock(Block)) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - m_LinkedPoweredBlocks.erase(itr); - break; + itr = LinkedPoweredBlocks->erase(itr); + continue; } } + ++itr; } - for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr) + SimulatedPlayerToggleableList * SimulatedPlayerToggleableBlocks = a_Chunk->GetRedstoneSimulatorSimulatedPlayerToggleableList(); + for (SimulatedPlayerToggleableList::iterator itr = SimulatedPlayerToggleableBlocks->begin(); itr != SimulatedPlayerToggleableBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -144,12 +163,13 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B if (!IsAllowedBlock(Block)) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - m_SimulatedPlayerToggleableBlocks.erase(itr); + SimulatedPlayerToggleableBlocks->erase(itr); break; } } - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) + RepeatersDelayList * RepeatersDelayList = a_Chunk->GetRedstoneSimulatorRepeatersDelayList(); + for (RepeatersDelayList::iterator itr = RepeatersDelayList->begin(); itr != RepeatersDelayList->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -158,13 +178,19 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF)) { - m_RepeatersDelayList.erase(itr); + RepeatersDelayList->erase(itr); break; } } - cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); - for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr) + if (a_OtherChunk != NULL) + { + // DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P + return; + } + + cRedstoneSimulatorChunkData * RedstoneSimulatorChunkData = a_Chunk->GetRedstoneSimulatorData(); + for (cRedstoneSimulatorChunkData::iterator itr = RedstoneSimulatorChunkData->begin(); itr != RedstoneSimulatorChunkData->end(); ++itr) { if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) // We are at an entry matching the current (changed) block { @@ -185,7 +211,7 @@ void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_B return; } - ChunkData.push_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false)); + RedstoneSimulatorChunkData->push_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false)); } @@ -199,20 +225,26 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int // The easiest way to make this more efficient is probably just to reduce code within the handlers that put too much strain on server, like getting or setting blocks // A marking dirty system might be a TODO for later on, perhaps - cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); - if (ChunkData.empty()) + m_RedstoneSimulatorChunkData = a_Chunk->GetRedstoneSimulatorData(); + if (m_RedstoneSimulatorChunkData->empty()) { return; } + m_PoweredBlocks = a_Chunk->GetRedstoneSimulatorPoweredBlocksList(); + m_RepeatersDelayList = a_Chunk->GetRedstoneSimulatorRepeatersDelayList(); + m_SimulatedPlayerToggleableBlocks = a_Chunk->GetRedstoneSimulatorSimulatedPlayerToggleableList(); + m_LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList(); + m_Chunk = a_Chunk; + int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; - for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(); dataitr != ChunkData.end();) + for (cRedstoneSimulatorChunkData::iterator dataitr = m_RedstoneSimulatorChunkData->begin(); dataitr != m_RedstoneSimulatorChunkData->end();) { if (dataitr->DataTwo) { - dataitr = ChunkData.erase(dataitr); + dataitr = m_RedstoneSimulatorChunkData->erase(dataitr); continue; } @@ -285,6 +317,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data); break; } + default: LOGD("Unhandled block (!) or unimplemented redstone block: %s", ItemToString(dataitr->Data).c_str()); break; } ++dataitr; } @@ -293,6 +326,35 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int +void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +{ + if ( + ((a_BlockX % cChunkDef::Width) <= 1) || + ((a_BlockX % cChunkDef::Width) >= 14) || + ((a_BlockZ % cChunkDef::Width) <= 1) || + ((a_BlockZ % cChunkDef::Width) >= 14) + ) // Are we on a chunk boundary? ± 2 because of LinkedPowered blocks + { + // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) + AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); + + // Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position + // RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordiantes are in and ± 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries + RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk); + RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk); + RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk); + RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 2), a_Chunk); + + return; + } + + // Not on boundary, just alert this chunk for speed + AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); +} + + + + void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) { @@ -318,22 +380,6 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc { // There was a match, torch goes off m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); - - float Pitch = (((1.0F-0.0F)*((float)rand()/RAND_MAX)) - ((1.0F-0.0F)*((float)rand()/RAND_MAX))) * 0.8F; - m_World.BroadcastSoundEffect("random.fizz", - ((int) (a_BlockX + 0.5F) * 8.0), - ((int) (a_BlockY + 0.5F) * 8.0), - ((int) (a_BlockZ + 0.5F) * 8.0), - 0.5F, - 2.6F + Pitch); - - for (int l = 0; l < 5; ++l) { - float d0 = a_BlockX + (double(rand())/RAND_MAX) * 0.6F + 0.2F; - float d1 = a_BlockY + (double(rand())/RAND_MAX) * 0.6F + 0.2F; - float d2 = a_BlockZ + (double(rand())/RAND_MAX) * 0.6F + 0.2F; - m_World.BroadcastParticleEffect("smoke", d0, d1, d2, 0.0F, 0.0F, 0.0F, 0.01F, 1); - } - return; } @@ -424,7 +470,7 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY, { cChunkInterface ChunkInterface(m_World.GetChunkMap()); NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) @@ -432,7 +478,7 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY, m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaData | 0x4); m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); - } + } } else { @@ -554,7 +600,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block } } - if (TimesMetaSmaller == TimesFoundAWire) + if ((TimesMetaSmaller == TimesFoundAWire) && (MyMeta != 0)) { // All surrounding metas were smaller - self must have been a wire that was // transferring power to other wires around. @@ -563,7 +609,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock return; // No need to process block power sets because self not powered } - else + else if (MyMeta != MetaToSet) { m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet); } @@ -587,12 +633,15 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block { case REDSTONE_NONE: { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_WIRE); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE); break; @@ -638,14 +687,14 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B if (IsSelfPowered && !IsOn) // Queue a power change if I am receiving power but not on { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, true); + QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, true); } else if (!IsSelfPowered && IsOn) // Queue a power change if I am not receiving power but on { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false); + QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, false); } - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) + for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -699,7 +748,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B { m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); } - m_RepeatersDelayList.erase(itr); // We can remove off repeaters which don't need further updating + m_RepeatersDelayList->erase(itr); // We can remove off repeaters which don't need further updating return; } } @@ -1060,7 +1109,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list + for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list { if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -1076,7 +1125,7 @@ bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list { if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -1094,7 +1143,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY { // Repeaters cannot be powered by any face except their back; verify that this is true for a source - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) + for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } @@ -1124,7 +1173,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY } } - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } @@ -1165,7 +1214,7 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ; eBlockFace Face = cPiston::MetaDataToDirection(a_Meta); - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) + for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } @@ -1181,7 +1230,7 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, a_BlockZ = OldZ; } - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } @@ -1204,7 +1253,7 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ) { - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) + for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } @@ -1214,7 +1263,7 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, in } } - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } @@ -1232,7 +1281,7 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, in bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered) { - for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr) + for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) { if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -1375,7 +1424,9 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, return; } - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list + PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); + + for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list { if ( itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && @@ -1390,7 +1441,7 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, sPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); - m_PoweredBlocks.push_back(RC); + Powered->push_back(RC); } @@ -1415,7 +1466,9 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( return; } - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list + LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); + + for (LinkedBlocksList::const_iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list { if ( itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && @@ -1432,7 +1485,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); - m_LinkedPoweredBlocks.push_back(RC); + Linked->push_back(RC); } @@ -1441,7 +1494,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered) { - for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr) + for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -1465,16 +1518,16 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Bl sSimulatedPlayerToggleableList RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.WasLastStatePowered = WasLastStatePowered; - m_SimulatedPlayerToggleableBlocks.push_back(RC); + m_SimulatedPlayerToggleableBlocks->push_back(RC); } -void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn) +void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn) { - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) + for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) { if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -1484,7 +1537,7 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a } // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit - itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; // See below for description + itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description itr->a_ElapsedTicks = 0; itr->ShouldPowerOn = ShouldPowerOn; return; @@ -1492,18 +1545,16 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a } // Self not in list, add self to list - sRepeatersDelayList RC; + sRepeatersDelayList RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed - // We don't +1 when powering off because everything seems to already delay a tick when powering off, why? No idea :P - RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; - + RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; RC.a_ElapsedTicks = 0; RC.ShouldPowerOn = ShouldPowerOn; - m_RepeatersDelayList.push_back(RC); + m_RepeatersDelayList->push_back(RC); return; } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index bcf89bb82..e6bc28621 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -3,7 +3,7 @@ #include "RedstoneSimulator.h" -/// Per-chunk data for the simulator, specified individual chunks to simulate; 'Data' is not used +/// Per-chunk data for the simulator, specified individual chunks to simulate typedef cCoordWithBlockAndBoolVector cRedstoneSimulatorChunkData; @@ -21,7 +21,8 @@ public: virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return IsRedstone(a_BlockType); } + virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override { return IsRedstone(a_BlockType); } + virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; enum eRedstoneDirection { @@ -57,22 +58,29 @@ private: struct sRepeatersDelayList { Vector3i a_BlockPos; - short a_DelayTicks; - short a_ElapsedTicks; + unsigned char a_DelayTicks; + unsigned char a_ElapsedTicks; bool ShouldPowerOn; }; - + +public: + typedef std::vector <sPoweredBlocks> PoweredBlocksList; typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList; typedef std::vector <sSimulatedPlayerToggleableList> SimulatedPlayerToggleableList; typedef std::vector <sRepeatersDelayList> RepeatersDelayList; - PoweredBlocksList m_PoweredBlocks; - LinkedBlocksList m_LinkedPoweredBlocks; - SimulatedPlayerToggleableList m_SimulatedPlayerToggleableBlocks; - RepeatersDelayList m_RepeatersDelayList; +private: + + cRedstoneSimulatorChunkData * m_RedstoneSimulatorChunkData; + PoweredBlocksList * m_PoweredBlocks; + LinkedBlocksList * m_LinkedPoweredBlocks; + SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks; + RepeatersDelayList * m_RepeatersDelayList; - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override { RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); } + void RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk = NULL); + cChunk * m_Chunk; // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly // In addition to being non-performant, it would stop the player from actually breaking said device @@ -84,8 +92,6 @@ private: void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ); /** Handles levers */ void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ); - /** Handles Fence Gates */ - void HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ); /** Handles buttons */ void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); /** Handles daylight sensors */ @@ -118,6 +124,8 @@ private: void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); /** Handles trapdoors */ void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ); + /** Handles fence gates */ + void HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ); /** Handles noteblocks */ void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ); /* ===================== */ @@ -134,7 +142,7 @@ private: /** Marks all blocks immediately surrounding a coordinate as powered */ void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock); /** Queues a repeater to be powered or unpowered */ - void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn); + void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); /** Returns if a coordinate is powered or linked powered */ bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); } @@ -267,3 +275,7 @@ private: } } }; + + + + |