From ce030bc7c9838a2c0c60b18a0e53bb40ff0fda26 Mon Sep 17 00:00:00 2001 From: Tycho Date: Fri, 17 Jan 2014 10:07:33 -0800 Subject: Implemented xsofts suggestion for a saturating counter in the scheduler --- src/World.cpp | 10 +++++----- src/World.h | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/World.cpp b/src/World.cpp index edf27050d..e4c03699f 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -875,10 +875,6 @@ void cWorld::TickScheduledTasks() Tasks.push_back(m_ScheduledTasks.front()); m_ScheduledTasks.pop_front(); } - for(;itr != m_ScheduledTasks.end(); itr++) - { - (*itr)->Ticks--; - } } // Execute and delete each task: @@ -887,6 +883,9 @@ void cWorld::TickScheduledTasks() (*itr)->Run(*this); delete *itr; } // for itr - m_Tasks[] + + // Increment TickID + m_TickID = (m_TickID+1) &0xFFFF; } @@ -2623,10 +2622,11 @@ void cWorld::QueueTask(cTask * a_Task) void cWorld::ScheduleTask(cScheduledTask * a_Task) { + a_Task->Ticks = (a_Task->Ticks + m_TickID) & 0xFFFF; cCSLock Lock(m_CSScheduledTasks); for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++) { - if((*itr)->Ticks >= a_Task->Ticks) + if((*itr)->Ticks >= a_Task->Ticks && (a_Task->Ticks > m_TickID || (*itr)->Ticks < m_TickID)) { m_ScheduledTasks.insert(itr, a_Task); return; diff --git a/src/World.h b/src/World.h index 1ecf41507..2fd7319cf 100644 --- a/src/World.h +++ b/src/World.h @@ -772,6 +772,9 @@ private: /// the future; guarded by m_CSScheduledTasks ScheduledTaskList m_ScheduledTasks; + /// Current Tick number for sceduled tasks + int m_TickID; + /// Guards m_Clients cCriticalSection m_CSClients; -- cgit v1.2.3 From 287144839e446001015b70a34146c6f321812eda Mon Sep 17 00:00:00 2001 From: Tycho Date: Fri, 17 Jan 2014 10:23:40 -0800 Subject: Increased tick count to long --- src/World.cpp | 4 ++-- src/World.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/World.cpp b/src/World.cpp index e4c03699f..f4b5f1ad8 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -885,7 +885,7 @@ void cWorld::TickScheduledTasks() } // for itr - m_Tasks[] // Increment TickID - m_TickID = (m_TickID+1) &0xFFFF; + m_TickID = (m_TickID+1) & 0x7FFFFFFF; } @@ -2622,7 +2622,7 @@ void cWorld::QueueTask(cTask * a_Task) void cWorld::ScheduleTask(cScheduledTask * a_Task) { - a_Task->Ticks = (a_Task->Ticks + m_TickID) & 0xFFFF; + a_Task->Ticks = (a_Task->Ticks + m_TickID) & 0x7FFFFFFF; cCSLock Lock(m_CSScheduledTasks); for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++) { diff --git a/src/World.h b/src/World.h index 2fd7319cf..1fe2740ad 100644 --- a/src/World.h +++ b/src/World.h @@ -773,7 +773,7 @@ private: ScheduledTaskList m_ScheduledTasks; /// Current Tick number for sceduled tasks - int m_TickID; + long m_TickID; /// Guards m_Clients cCriticalSection m_CSClients; -- cgit v1.2.3 From 160a27ccedf0aa8590bcf03abc9154eb1ee7b72d Mon Sep 17 00:00:00 2001 From: Tycho Date: Sat, 18 Jan 2014 06:15:33 -0800 Subject: switched to using m_WorldAge rather than m_TickID --- src/World.cpp | 9 +++------ src/World.h | 3 --- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/World.cpp b/src/World.cpp index f4b5f1ad8..a466acb84 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -870,7 +870,7 @@ void cWorld::TickScheduledTasks() { cCSLock Lock(m_CSScheduledTasks); ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); - while (itr != m_ScheduledTasks.end() && (*itr)->Ticks > 0) + while (itr != m_ScheduledTasks.end() && (*itr)->Ticks < m_WorldAge) { Tasks.push_back(m_ScheduledTasks.front()); m_ScheduledTasks.pop_front(); @@ -883,9 +883,6 @@ void cWorld::TickScheduledTasks() (*itr)->Run(*this); delete *itr; } // for itr - m_Tasks[] - - // Increment TickID - m_TickID = (m_TickID+1) & 0x7FFFFFFF; } @@ -2622,11 +2619,11 @@ void cWorld::QueueTask(cTask * a_Task) void cWorld::ScheduleTask(cScheduledTask * a_Task) { - a_Task->Ticks = (a_Task->Ticks + m_TickID) & 0x7FFFFFFF; + a_Task->Ticks = a_Task->Ticks + m_WorldAge; cCSLock Lock(m_CSScheduledTasks); for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++) { - if((*itr)->Ticks >= a_Task->Ticks && (a_Task->Ticks > m_TickID || (*itr)->Ticks < m_TickID)) + if((*itr)->Ticks >= a_Task->Ticks) { m_ScheduledTasks.insert(itr, a_Task); return; diff --git a/src/World.h b/src/World.h index 1fe2740ad..1ecf41507 100644 --- a/src/World.h +++ b/src/World.h @@ -772,9 +772,6 @@ private: /// the future; guarded by m_CSScheduledTasks ScheduledTaskList m_ScheduledTasks; - /// Current Tick number for sceduled tasks - long m_TickID; - /// Guards m_Clients cCriticalSection m_CSClients; -- cgit v1.2.3 From d93a4362b4275d94efe9a40a76a095d52448d0d8 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sat, 18 Jan 2014 10:57:25 -0800 Subject: Fixed iterators bug --- src/World.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/World.cpp b/src/World.cpp index a466acb84..134773f67 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -869,8 +869,7 @@ void cWorld::TickScheduledTasks() // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks { cCSLock Lock(m_CSScheduledTasks); - ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); - while (itr != m_ScheduledTasks.end() && (*itr)->Ticks < m_WorldAge) + while (!m_ScheduledTasks.empty() && m_ScheduledTasks.front()->Ticks < m_WorldAge) { Tasks.push_back(m_ScheduledTasks.front()); m_ScheduledTasks.pop_front(); -- cgit v1.2.3 From f8c8dcc7f36366dc6b59e6741d466e739322d5d1 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 19 Jan 2014 00:54:38 +0000 Subject: Improved command blocks * Their command and previous output are displayed on the client * They have a BlockHandler implementation, so you can't place blocks on them anymore + As a side effect, implemented UpdateBlockEntity --- src/BlockEntities/CommandBlockEntity.cpp | 42 ++++++++++++++++++++++++++++---- src/Blocks/BlockCommandBlock.h | 32 ++++++++++++++++++++++++ src/Blocks/BlockHandler.cpp | 2 ++ src/ClientHandle.cpp | 9 +++++++ src/ClientHandle.h | 2 ++ src/Protocol/Protocol.h | 2 ++ src/Protocol/Protocol125.h | 1 + src/Protocol/Protocol17x.cpp | 25 +++++++++++++++++++ src/Protocol/Protocol17x.h | 2 ++ src/Protocol/ProtocolRecognizer.cpp | 10 ++++++++ src/Protocol/ProtocolRecognizer.h | 2 ++ 11 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 src/Blocks/BlockCommandBlock.h (limited to 'src') diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 543d47b7a..6e5c8087e 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -7,10 +7,11 @@ #include "json/json.h" #include "CommandBlockEntity.h" #include "../Entities/Player.h" +#include "../WorldStorage/FastNBT.h" -#include "CommandOutput.h" -#include "Root.h" -#include "Server.h" // ExecuteConsoleCommand() +#include "../CommandOutput.h" +#include "../Root.h" +#include "../Server.h" // ExecuteConsoleCommand() @@ -40,6 +41,15 @@ void cCommandBlockEntity::UsedBy(cPlayer * a_Player) void cCommandBlockEntity::SetCommand(const AString & a_Cmd) { m_Command = a_Cmd; + + /* + Vanilla requires that the server send a Block Entity Update after a command has been set + Therefore, command blocks don't support on-the-fly (when window is open) updating of a command and therefore... + ...the following code can't be put in UsedBy just before the window opens + + Just documenting my experience in getting this to work :P + */ + m_World->BroadcastBlockEntity(GetPosX(), GetPosY(), GetPosZ()); } @@ -131,8 +141,30 @@ bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk) void cCommandBlockEntity::SendTo(cClientHandle & a_Client) { - // Nothing needs to be sent - UNUSED(a_Client); + cFastNBTWriter Writer; + Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this + Writer.AddInt("SuccessCount", GetResult()); + Writer.AddInt("x", GetPosX()); + Writer.AddInt("y", GetPosY()); + Writer.AddInt("z", GetPosZ()); + Writer.AddString("Command", GetCommand().c_str()); + // You can set custom names for windows in Vanilla + // For a command block, this would be the 'name' prepended to anything it outputs into global chat + // MCS doesn't have this, so just leave it @ '@'. (geddit?) + Writer.AddString("CustomName", "@"); + Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + + if (!GetLastOutput().empty()) + { + AString Output; + Printf(Output, "{\"text\":\"%s\"}", GetLastOutput().c_str()); + + Writer.AddString("LastOutput", Output.c_str()); + } + + Writer.Finish(); + + a_Client.SendUpdateBlockEntity(GetPosX(), GetPosY(), GetPosZ(), 2, Writer); } diff --git a/src/Blocks/BlockCommandBlock.h b/src/Blocks/BlockCommandBlock.h new file mode 100644 index 000000000..cf0103765 --- /dev/null +++ b/src/Blocks/BlockCommandBlock.h @@ -0,0 +1,32 @@ + +#pragma once + +#include "BlockEntity.h" + + + + + +class cBlockCommandBlockHandler : + public cBlockEntityHandler +{ +public: + cBlockCommandBlockHandler(BLOCKTYPE a_BlockType) + : cBlockEntityHandler(a_BlockType) + { + } + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + a_Pickups.push_back(cItem(E_BLOCK_AIR, 8, 0)); + } + + virtual const char * GetStepSound(void) override + { + return "step.stone"; + } +} ; + + + + diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index ff1022e12..b9c0887ce 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -14,6 +14,7 @@ #include "BlockChest.h" #include "BlockCloth.h" #include "BlockCobWeb.h" +#include "BlockCommandBlock.h" #include "BlockComparator.h" #include "BlockCrops.h" #include "BlockDeadBush.h" @@ -116,6 +117,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType); case E_BLOCK_CHEST: return new cBlockChestHandler (a_BlockType); case E_BLOCK_COAL_ORE: return new cBlockOreHandler (a_BlockType); + case E_BLOCK_COMMAND_BLOCK: return new cBlockCommandBlockHandler (a_BlockType); case E_BLOCK_ACTIVE_COMPARATOR: return new cBlockComparatorHandler (a_BlockType); case E_BLOCK_COBBLESTONE: return new cBlockStoneHandler (a_BlockType); case E_BLOCK_COBBLESTONE_STAIRS: return new cBlockStairsHandler (a_BlockType); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index faf583fbb..93dc78642 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -20,6 +20,7 @@ #include "Items/ItemHandler.h" #include "Blocks/BlockHandler.h" #include "Blocks/BlockSlab.h" +#include "WorldStorage/FastNBT.h" #include "Vector3f.h" #include "Vector3d.h" @@ -2203,6 +2204,14 @@ void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +void cClientHandle::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) +{ + m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_NBT); +} + + + + void cClientHandle::SendUpdateSign( int a_BlockX, int a_BlockY, int a_BlockZ, diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 373ca9e2e..2ac240b17 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -16,6 +16,7 @@ #include "OSSupport/SocketThreads.h" #include "ChunkDef.h" #include "ByteBuffer.h" +#include "WorldStorage/FastNBT.h" @@ -136,6 +137,7 @@ public: void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay); void SendUnloadChunk (int a_ChunkX, int a_ChunkZ); + void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT); void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); void SendWeather (eWeather a_Weather); diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 3293da32c..6af0af25d 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -12,6 +12,7 @@ #include "../Defines.h" #include "../Endianness.h" +#include "../WorldStorage/FastNBT.h" @@ -103,6 +104,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) = 0; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0; virtual void SendWeather (eWeather a_Weather) = 0; diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index d0e5c9428..97b194d76 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -79,6 +79,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) override {}; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 5b3a79555..01a6b0bde 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -892,6 +892,20 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +void cProtocol172::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) +{ + cPacketizer Pkt(*this, 0x35); // Update tile entity packet + Pkt.WriteInt(a_BlockX); + Pkt.WriteShort(a_BlockY); + Pkt.WriteInt(a_BlockZ); + Pkt.WriteByte(a_Action); + + Pkt.WriteBlockEntity(a_NBT); +} + + + + void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) { @@ -1819,6 +1833,17 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) +void cProtocol172::cPacketizer::WriteBlockEntity(const cFastNBTWriter & a_NBT) +{ + AString Compressed; + CompressStringGZIP(a_NBT.GetResult().data(), a_NBT.GetResult().size(), Compressed); + WriteShort(Compressed.size()); + WriteBuf(Compressed.data(), Compressed.size()); +} + + + + void cProtocol172::cPacketizer::WriteByteAngle(double a_Angle) { diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 07dba834b..6e04a0ffb 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -102,6 +102,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; @@ -189,6 +190,7 @@ protected: void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob void WriteEntityProperties(const cEntity & a_Entity); // Writes the entity properties for the specified entity, including the Count field + void WriteBlockEntity(const cFastNBTWriter & a_NBT); protected: cProtocol172 & m_Protocol; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index a21f4f042..579469fb4 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -636,6 +636,16 @@ void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +void cProtocolRecognizer::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_NBT); +} + + + + + void cProtocolRecognizer::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) { ASSERT(m_Protocol != NULL); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index e94f4cde8..410ba556e 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -12,6 +12,7 @@ #include "Protocol.h" #include "../ByteBuffer.h" +#include "../WorldStorage/FastNBT.h" @@ -114,6 +115,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; -- cgit v1.2.3 From a85b2897e0e9563be69ed2fde944573459103d56 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 19 Jan 2014 01:06:19 +0000 Subject: Implemented MC|Brand response --- src/ClientHandle.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 93dc78642..8f95212e1 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -547,12 +547,18 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message) { - if (a_Channel == "MC|AdvCdm") // Command block + if (a_Channel == "MC|AdvCdm") // Command block, set text, Client -> Server { const char* Data = a_Message.c_str(); - HandleCommandBlockMessage(Data, a_Message.size()); - + return; + } + else if (a_Channel == "MC|Brand") // Client <-> Server branding exchange + { + // We are custom, + // We are awesome, + // We are MCServer. + SendPluginMessage("MC|Brand", "MCServer"); return; } -- cgit v1.2.3 From 1af89a8b50a382ef0f5c137a84ab2816c45cc73c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 19 Jan 2014 13:25:35 +0000 Subject: Changed SendBlockEntity format slightly * Writing NBT is now in Protocol, not BlockEntity files * Fixed a last output bug --- src/BlockEntities/CommandBlockEntity.cpp | 26 ++----------------- src/ClientHandle.cpp | 9 ++++--- src/ClientHandle.h | 3 +-- src/Protocol/Protocol.h | 3 +-- src/Protocol/Protocol125.h | 2 +- src/Protocol/Protocol17x.cpp | 43 +++++++++++++++++++++++++++++--- src/Protocol/Protocol17x.h | 4 +-- src/Protocol/ProtocolRecognizer.cpp | 4 +-- src/Protocol/ProtocolRecognizer.h | 3 +-- 9 files changed, 55 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 6e5c8087e..38737d619 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -58,6 +58,7 @@ void cCommandBlockEntity::SetCommand(const AString & a_Cmd) void cCommandBlockEntity::SetLastOutput(const AString & a_LastOut) { + m_World->BroadcastBlockEntity(GetPosX(), GetPosY(), GetPosZ()); m_LastOutput = a_LastOut; } @@ -141,30 +142,7 @@ bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk) void cCommandBlockEntity::SendTo(cClientHandle & a_Client) { - cFastNBTWriter Writer; - Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this - Writer.AddInt("SuccessCount", GetResult()); - Writer.AddInt("x", GetPosX()); - Writer.AddInt("y", GetPosY()); - Writer.AddInt("z", GetPosZ()); - Writer.AddString("Command", GetCommand().c_str()); - // You can set custom names for windows in Vanilla - // For a command block, this would be the 'name' prepended to anything it outputs into global chat - // MCS doesn't have this, so just leave it @ '@'. (geddit?) - Writer.AddString("CustomName", "@"); - Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - - if (!GetLastOutput().empty()) - { - AString Output; - Printf(Output, "{\"text\":\"%s\"}", GetLastOutput().c_str()); - - Writer.AddString("LastOutput", Output.c_str()); - } - - Writer.Finish(); - - a_Client.SendUpdateBlockEntity(GetPosX(), GetPosY(), GetPosZ(), 2, Writer); + a_Client.SendUpdateBlockEntity(GetPosX(), GetPosY(), GetPosZ(), 2, *this); } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 8f95212e1..327fc0358 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -20,7 +20,6 @@ #include "Items/ItemHandler.h" #include "Blocks/BlockHandler.h" #include "Blocks/BlockSlab.h" -#include "WorldStorage/FastNBT.h" #include "Vector3f.h" #include "Vector3d.h" @@ -573,6 +572,7 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a { if (a_Length < 14) { + SendChat(Printf("%s[INFO]%s Failure setting command block command; bad request", cChatColor::Red.c_str(), cChatColor::White.c_str())); LOGD("Malformed MC|AdvCdm packet."); return; } @@ -602,6 +602,7 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a default: { + SendChat(Printf("%s[INFO]%s Failure setting command block command; unhandled mode", cChatColor::Red.c_str(), cChatColor::White.c_str())); LOGD("Unhandled MC|AdvCdm packet mode."); return; } @@ -624,6 +625,8 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a cWorld * World = m_Player->GetWorld(); World->DoWithCommandBlockAt(BlockX, BlockY, BlockZ, CmdBlockCB); + + SendChat(Printf("%s[INFO]%s Successfully set command block command", cChatColor::Green.c_str(), cChatColor::White.c_str())); } @@ -2210,9 +2213,9 @@ void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -void cClientHandle::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) +void cClientHandle::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) { - m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_NBT); + m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_BlockEntity); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 2ac240b17..daa185ca0 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -16,7 +16,6 @@ #include "OSSupport/SocketThreads.h" #include "ChunkDef.h" #include "ByteBuffer.h" -#include "WorldStorage/FastNBT.h" @@ -137,7 +136,7 @@ public: void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay); void SendUnloadChunk (int a_ChunkX, int a_ChunkZ); - void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT); + void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity); void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); void SendWeather (eWeather a_Weather); diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 6af0af25d..ac925e382 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -12,7 +12,6 @@ #include "../Defines.h" #include "../Endianness.h" -#include "../WorldStorage/FastNBT.h" @@ -104,7 +103,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) = 0; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) = 0; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0; virtual void SendWeather (eWeather a_Weather) = 0; diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 97b194d76..ec72ddd01 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -79,7 +79,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) override {}; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) override {}; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 01a6b0bde..c85641ca8 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -24,6 +24,7 @@ Implements the 1.7.x protocol classes: #include "../Entities/Player.h" #include "../Mobs/IncludeAllMonsters.h" #include "../UI/Window.h" +#include "../BlockEntities/CommandBlockEntity.h" @@ -892,7 +893,7 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -void cProtocol172::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) +void cProtocol172::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) { cPacketizer Pkt(*this, 0x35); // Update tile entity packet Pkt.WriteInt(a_BlockX); @@ -900,7 +901,7 @@ void cProtocol172::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_Block Pkt.WriteInt(a_BlockZ); Pkt.WriteByte(a_Action); - Pkt.WriteBlockEntity(a_NBT); + Pkt.WriteBlockEntity(a_BlockEntity); } @@ -1833,10 +1834,44 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) -void cProtocol172::cPacketizer::WriteBlockEntity(const cFastNBTWriter & a_NBT) +void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEntity) { + cFastNBTWriter Writer; + + switch (a_BlockEntity.GetBlockType()) + { + case E_BLOCK_COMMAND_BLOCK: + { + cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity; + + Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this + Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); + Writer.AddInt("x", CommandBlockEntity.GetPosX()); + Writer.AddInt("y", CommandBlockEntity.GetPosY()); + Writer.AddInt("z", CommandBlockEntity.GetPosZ()); + Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str()); + // You can set custom names for windows in Vanilla + // For a command block, this would be the 'name' prepended to anything it outputs into global chat + // MCS doesn't have this, so just leave it @ '@'. (geddit?) + Writer.AddString("CustomName", "@"); + Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + + if (!CommandBlockEntity.GetLastOutput().empty()) + { + AString Output; + Printf(Output, "{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str()); + + Writer.AddString("LastOutput", Output.c_str()); + } + break; + } + default: break; + } + + Writer.Finish(); + AString Compressed; - CompressStringGZIP(a_NBT.GetResult().data(), a_NBT.GetResult().size(), Compressed); + CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); WriteShort(Compressed.size()); WriteBuf(Compressed.data(), Compressed.size()); } diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 6e04a0ffb..b1d902507 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -102,7 +102,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) override; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; @@ -190,7 +190,7 @@ protected: void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob void WriteEntityProperties(const cEntity & a_Entity); // Writes the entity properties for the specified entity, including the Count field - void WriteBlockEntity(const cFastNBTWriter & a_NBT); + void WriteBlockEntity(const cBlockEntity & a_BlockEntity); protected: cProtocol172 & m_Protocol; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 579469fb4..86f46f02f 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -636,10 +636,10 @@ void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -void cProtocolRecognizer::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) +void cProtocolRecognizer::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) { ASSERT(m_Protocol != NULL); - m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_NBT); + m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_BlockEntity); } diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 410ba556e..c1c8abdd5 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -12,7 +12,6 @@ #include "Protocol.h" #include "../ByteBuffer.h" -#include "../WorldStorage/FastNBT.h" @@ -115,7 +114,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cFastNBTWriter & a_NBT) override; + virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; -- cgit v1.2.3 From dc70d04cddee5d4888fa22854d291bfee0cfc293 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 18 Jan 2014 20:50:16 +0100 Subject: SocketThreads: Removed unused code. --- src/OSSupport/SocketThreads.cpp | 51 ----------------------------------------- src/OSSupport/SocketThreads.h | 5 ++-- 2 files changed, 3 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp index 3e505616c..b222a2e4e 100644 --- a/src/OSSupport/SocketThreads.cpp +++ b/src/OSSupport/SocketThreads.cpp @@ -71,29 +71,6 @@ bool cSocketThreads::AddClient(const cSocket & a_Socket, cCallback * a_Client) -/* -void cSocketThreads::RemoveClient(const cSocket * a_Socket) -{ - // Remove the socket (and associated client) from processing - - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->RemoveSocket(a_Socket)) - { - return; - } - } // for itr - m_Threads[] - - // Cannot assert here, this may actually happen legally, since cClientHandle has to clean up the socket and it may have already closed in the meantime - // ASSERT(!"Removing an unknown socket"); -} -*/ - - - - - void cSocketThreads::RemoveClient(const cCallback * a_Client) { // Remove the associated socket and the client from processing @@ -284,34 +261,6 @@ bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client) -bool cSocketThreads::cSocketThread::RemoveSocket(const cSocket * a_Socket) -{ - // Returns true if removed, false if not found - - for (int i = m_NumSlots - 1; i >= 0 ; --i) - { - if (m_Slots[i].m_Socket != *a_Socket) - { - continue; - } - - // Found, remove it: - m_Slots[i] = m_Slots[--m_NumSlots]; - - // Notify the thread of the change: - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("r", 1); - return true; - } // for i - m_Slots[] - - // Not found - return false; -} - - - - - bool cSocketThreads::cSocketThread::HasClient(const cCallback * a_Client) const { for (int i = m_NumSlots - 1; i >= 0; --i) diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h index 858729c49..e16ae69fb 100644 --- a/src/OSSupport/SocketThreads.h +++ b/src/OSSupport/SocketThreads.h @@ -81,7 +81,9 @@ public: /// Add a (socket, client) pair for processing, data from a_Socket is to be sent to a_Client; returns true if successful bool AddClient(const cSocket & a_Socket, cCallback * a_Client); - /// Remove the associated socket and the client from processing. The socket is left to send its data and is removed only after all its m_OutgoingData is sent + /** Remove the associated socket and the client from processing. + The socket is left to send its data and is removed only after all its m_OutgoingData is sent + */ void RemoveClient(const cCallback * a_Client); /// Notify the thread responsible for a_Client that the client has something to write @@ -114,7 +116,6 @@ private: void AddClient (const cSocket & a_Socket, cCallback * a_Client); // Takes ownership of the socket bool RemoveClient(const cCallback * a_Client); // Returns true if removed, false if not found - bool RemoveSocket(const cSocket * a_Socket); // Returns true if removed, false if not found bool HasClient (const cCallback * a_Client) const; bool HasSocket (const cSocket * a_Socket) const; bool NotifyWrite (const cCallback * a_Client); // Returns true if client handled by this thread -- cgit v1.2.3 From e14ddff1c00919f1416bfa6da9568e2dff419559 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 19 Jan 2014 07:38:59 -0800 Subject: Spilt Writing of Enchantments to seperate class Created a new class cEnchantmentSerializer to serilize Enchantments to NBT. This breaks a dependecy chain between cChunkGenerator and cWorld. cEnchantmentSerializer is seperate from NBTWriter as it needs to access private members of cEnchantments so having it seperate reduces the spread of the frein modifier --- src/Enchantments.cpp | 79 --------------------------- src/Enchantments.h | 7 +-- src/Protocol/Protocol132.cpp | 5 +- src/Protocol/Protocol17x.cpp | 5 +- src/WorldStorage/EnchantmentSerializer.cpp | 87 ++++++++++++++++++++++++++++++ src/WorldStorage/EnchantmentSerializer.h | 17 ++++++ src/WorldStorage/NBTChunkSerializer.cpp | 3 +- src/WorldStorage/WSSAnvil.cpp | 3 +- 8 files changed, 116 insertions(+), 90 deletions(-) create mode 100644 src/WorldStorage/EnchantmentSerializer.cpp create mode 100644 src/WorldStorage/EnchantmentSerializer.h (limited to 'src') diff --git a/src/Enchantments.cpp b/src/Enchantments.cpp index 95ca201f0..1d8188e96 100644 --- a/src/Enchantments.cpp +++ b/src/Enchantments.cpp @@ -213,87 +213,8 @@ bool cEnchantments::operator !=(const cEnchantments & a_Other) const -void cEnchantments::WriteToNBTCompound(cFastNBTWriter & a_Writer, const AString & a_ListTagName) const -{ - // Write the enchantments into the specified NBT writer - // begin with the LIST tag of the specified name ("ench" or "StoredEnchantments") - - a_Writer.BeginList(a_ListTagName, TAG_Compound); - for (cMap::const_iterator itr = m_Enchantments.begin(), end = m_Enchantments.end(); itr != end; ++itr) - { - a_Writer.BeginCompound(""); - a_Writer.AddShort("id", itr->first); - a_Writer.AddShort("lvl", itr->second); - a_Writer.EndCompound(); - } // for itr - m_Enchantments[] - a_Writer.EndList(); -} - -void cEnchantments::ParseFromNBT(const cParsedNBT & a_NBT, int a_EnchListTagIdx) -{ - // Read the enchantments from the specified NBT list tag (ench or StoredEnchantments) - - // Verify that the tag is a list: - if (a_NBT.GetType(a_EnchListTagIdx) != TAG_List) - { - LOGWARNING("%s: Invalid EnchListTag type: exp %d, got %d. Enchantments not parsed", - __FUNCTION__, TAG_List, a_NBT.GetType(a_EnchListTagIdx) - ); - ASSERT(!"Bad EnchListTag type"); - return; - } - - // Verify that the list is of Compounds: - if (a_NBT.GetChildrenType(a_EnchListTagIdx) != TAG_Compound) - { - LOGWARNING("%s: Invalid NBT list children type: exp %d, got %d. Enchantments not parsed", - __FUNCTION__, TAG_Compound, a_NBT.GetChildrenType(a_EnchListTagIdx) - ); - ASSERT(!"Bad EnchListTag children type"); - return; - } - - Clear(); - - // Iterate over all the compound children, parse an enchantment from each: - for (int tag = a_NBT.GetFirstChild(a_EnchListTagIdx); tag >= 0; tag = a_NBT.GetNextSibling(tag)) - { - // tag is the compound inside the "ench" list tag - ASSERT(a_NBT.GetType(tag) == TAG_Compound); - - // Search for the id and lvl tags' values: - int id = -1, lvl = -1; - for (int ch = a_NBT.GetFirstChild(tag); ch >= 0; ch = a_NBT.GetNextSibling(ch)) - { - if (a_NBT.GetType(ch) != TAG_Short) - { - continue; - } - if (a_NBT.GetName(ch) == "id") - { - id = a_NBT.GetShort(ch); - } - else if (a_NBT.GetName(ch) == "lvl") - { - lvl = a_NBT.GetShort(ch); - } - } // for ch - children of the compound tag - - if ((id == -1) || (lvl <= 0)) - { - // Failed to parse either the id or the lvl, skip this compound - continue; - } - - // Store the enchantment: - m_Enchantments[id] = lvl; - } // for tag - children of the ench list tag -} - - - diff --git a/src/Enchantments.h b/src/Enchantments.h index 7581b87b5..0f23f8657 100644 --- a/src/Enchantments.h +++ b/src/Enchantments.h @@ -31,6 +31,7 @@ Serialization will never put zero-level enchantments into the stringspec and wil */ class cEnchantments { +friend class cEnchantmentSerializer; public: /// Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs ) enum @@ -96,11 +97,7 @@ public: /// Returns true if a_Other doesn't contain exactly the same enchantments and levels bool operator !=(const cEnchantments & a_Other) const; - /// Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") - void WriteToNBTCompound(cFastNBTWriter & a_Writer, const AString & a_ListTagName) const; - - /// Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) - void ParseFromNBT(const cParsedNBT & a_NBT, int a_EnchListTagIdx); + protected: /// Maps enchantment ID -> enchantment level diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index 29fbb4bba..501a8474e 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -16,6 +16,7 @@ #include "../UI/Window.h" #include "../Entities/Pickup.h" #include "../WorldStorage/FastNBT.h" +#include "../WorldStorage/EnchantmentSerializer.h" #include "../StringCompression.h" #ifdef _MSC_VER @@ -763,7 +764,7 @@ void cProtocol132::WriteItem(const cItem & a_Item) // Send the enchantments: cFastNBTWriter Writer; const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName); + cEnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName); Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); @@ -849,7 +850,7 @@ int cProtocol132::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) ) ) { - a_Item.m_Enchantments.ParseFromNBT(NBT, tag); + cEnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); } } diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 5b3a79555..44db659a5 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -16,6 +16,7 @@ Implements the 1.7.x protocol classes: #include "../Server.h" #include "../World.h" #include "../WorldStorage/FastNBT.h" +#include "../WorldStorage/EnchantmentSerializer.h" #include "../StringCompression.h" #include "../Entities/ExpOrb.h" #include "../Entities/Minecart.h" @@ -1696,7 +1697,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) ) ) { - a_Item.m_Enchantments.ParseFromNBT(NBT, tag); + cEnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); } else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag { @@ -1781,7 +1782,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) if (!a_Item.m_Enchantments.IsEmpty()) { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName); + cEnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments,Writer, TagName); } if (!a_Item.IsBothNameAndLoreEmpty()) { diff --git a/src/WorldStorage/EnchantmentSerializer.cpp b/src/WorldStorage/EnchantmentSerializer.cpp new file mode 100644 index 000000000..a481f1682 --- /dev/null +++ b/src/WorldStorage/EnchantmentSerializer.cpp @@ -0,0 +1,87 @@ + +#include "Globals.h" + +#include "EnchantmentSerializer.h" +#include "FastNBT.h" + +void cEnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName) +{ + // Write the enchantments into the specified NBT writer + // begin with the LIST tag of the specified name ("ench" or "StoredEnchantments") + + a_Writer.BeginList(a_ListTagName, TAG_Compound); + for (cEnchantments::cMap::const_iterator itr = a_Enchantments.m_Enchantments.begin(), end = a_Enchantments.m_Enchantments.end(); itr != end; ++itr) + { + a_Writer.BeginCompound(""); + a_Writer.AddShort("id", itr->first); + a_Writer.AddShort("lvl", itr->second); + a_Writer.EndCompound(); + } // for itr - m_Enchantments[] + a_Writer.EndList(); +} + + + + + +void cEnchantmentSerializer::ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx) +{ + // Read the enchantments from the specified NBT list tag (ench or StoredEnchantments) + + // Verify that the tag is a list: + if (a_NBT.GetType(a_EnchListTagIdx) != TAG_List) + { + LOGWARNING("%s: Invalid EnchListTag type: exp %d, got %d. Enchantments not parsed", + __FUNCTION__, TAG_List, a_NBT.GetType(a_EnchListTagIdx) + ); + ASSERT(!"Bad EnchListTag type"); + return; + } + + // Verify that the list is of Compounds: + if (a_NBT.GetChildrenType(a_EnchListTagIdx) != TAG_Compound) + { + LOGWARNING("%s: Invalid NBT list children type: exp %d, got %d. Enchantments not parsed", + __FUNCTION__, TAG_Compound, a_NBT.GetChildrenType(a_EnchListTagIdx) + ); + ASSERT(!"Bad EnchListTag children type"); + return; + } + + a_Enchantments.Clear(); + + // Iterate over all the compound children, parse an enchantment from each: + for (int tag = a_NBT.GetFirstChild(a_EnchListTagIdx); tag >= 0; tag = a_NBT.GetNextSibling(tag)) + { + // tag is the compound inside the "ench" list tag + ASSERT(a_NBT.GetType(tag) == TAG_Compound); + + // Search for the id and lvl tags' values: + int id = -1, lvl = -1; + for (int ch = a_NBT.GetFirstChild(tag); ch >= 0; ch = a_NBT.GetNextSibling(ch)) + { + if (a_NBT.GetType(ch) != TAG_Short) + { + continue; + } + if (a_NBT.GetName(ch) == "id") + { + id = a_NBT.GetShort(ch); + } + else if (a_NBT.GetName(ch) == "lvl") + { + lvl = a_NBT.GetShort(ch); + } + } // for ch - children of the compound tag + + if ((id == -1) || (lvl <= 0)) + { + // Failed to parse either the id or the lvl, skip this compound + continue; + } + + // Store the enchantment: + a_Enchantments.m_Enchantments[id] = lvl; + } // for tag - children of the ench list tag +} + diff --git a/src/WorldStorage/EnchantmentSerializer.h b/src/WorldStorage/EnchantmentSerializer.h new file mode 100644 index 000000000..d616b0f62 --- /dev/null +++ b/src/WorldStorage/EnchantmentSerializer.h @@ -0,0 +1,17 @@ + +#pragma once + +#include "Enchantments.h" + +class cEnchantmentSerializer +{ + +public: + + /// Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") + static void WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName); + + /// Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) + static void ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx); + +}; diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e1205f2be..51e1a8d1b 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -4,6 +4,7 @@ #include "Globals.h" #include "NBTChunkSerializer.h" +#include "EnchantmentSerializer.h" #include "../BlockID.h" #include "../ItemGrid.h" #include "../StringCompression.h" @@ -91,7 +92,7 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; m_Writer.BeginCompound("tag"); - a_Item.m_Enchantments.WriteToNBTCompound(m_Writer, TagName); + cEnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName); m_Writer.EndCompound(); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 16513cd1b..702b809fb 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -7,6 +7,7 @@ #include "WSSAnvil.h" #include "NBTChunkSerializer.h" #include "FastNBT.h" +#include "EnchantmentSerializer.h" #include "zlib/zlib.h" #include "../World.h" #include "../BlockID.h" @@ -639,7 +640,7 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ int EnchTag = a_NBT.FindChildByName(TagTag, EnchName); if (EnchTag > 0) { - a_Item.m_Enchantments.ParseFromNBT(a_NBT, EnchTag); + cEnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag); } return true; -- cgit v1.2.3 From f13a14d2cf4a7858c22fe003acff6753d0d50ba1 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 19 Jan 2014 08:52:45 -0800 Subject: Switched EnchantmentSerilizer to namespace --- src/Enchantments.h | 11 ++++++++--- src/Protocol/Protocol132.cpp | 4 ++-- src/Protocol/Protocol17x.cpp | 4 ++-- src/WorldStorage/EnchantmentSerializer.cpp | 5 +++-- src/WorldStorage/EnchantmentSerializer.h | 12 ++++++------ src/WorldStorage/NBTChunkSerializer.cpp | 2 +- src/WorldStorage/WSSAnvil.cpp | 2 +- 7 files changed, 23 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/Enchantments.h b/src/Enchantments.h index 0f23f8657..e984df92e 100644 --- a/src/Enchantments.h +++ b/src/Enchantments.h @@ -8,6 +8,7 @@ #pragma once +#include "WorldStorage/EnchantmentSerializer.h" @@ -20,7 +21,6 @@ class cParsedNBT; -// tolua_begin /** Class that stores item enchantments or stored-enchantments The enchantments may be serialized to a stringspec and read back from such stringspec. @@ -29,11 +29,12 @@ mapping each enchantment's id onto its level. ID may be either a number or the e Level value of 0 means no such enchantment, and it will not be stored in the m_Enchantments. Serialization will never put zero-level enchantments into the stringspec and will always use numeric IDs. */ +// tolua_begin class cEnchantments { -friend class cEnchantmentSerializer; public: /// Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs ) + enum { enchProtection = 0, @@ -97,7 +98,11 @@ public: /// Returns true if a_Other doesn't contain exactly the same enchantments and levels bool operator !=(const cEnchantments & a_Other) const; - + /// Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") + friend void EnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName); + + /// Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) + friend void EnchantmentSerializer::ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx); protected: /// Maps enchantment ID -> enchantment level diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index 501a8474e..b4ca37d37 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -764,7 +764,7 @@ void cProtocol132::WriteItem(const cItem & a_Item) // Send the enchantments: cFastNBTWriter Writer; const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - cEnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName); + EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName); Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); @@ -850,7 +850,7 @@ int cProtocol132::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) ) ) { - cEnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); + EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); } } diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 44db659a5..c64441a1e 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1697,7 +1697,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) ) ) { - cEnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); + EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); } else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag { @@ -1782,7 +1782,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) if (!a_Item.m_Enchantments.IsEmpty()) { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - cEnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments,Writer, TagName); + EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments,Writer, TagName); } if (!a_Item.IsBothNameAndLoreEmpty()) { diff --git a/src/WorldStorage/EnchantmentSerializer.cpp b/src/WorldStorage/EnchantmentSerializer.cpp index a481f1682..56072207f 100644 --- a/src/WorldStorage/EnchantmentSerializer.cpp +++ b/src/WorldStorage/EnchantmentSerializer.cpp @@ -2,9 +2,10 @@ #include "Globals.h" #include "EnchantmentSerializer.h" +#include "Enchantments.h" #include "FastNBT.h" -void cEnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName) +void EnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName) { // Write the enchantments into the specified NBT writer // begin with the LIST tag of the specified name ("ench" or "StoredEnchantments") @@ -24,7 +25,7 @@ void cEnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantme -void cEnchantmentSerializer::ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx) +void EnchantmentSerializer::ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx) { // Read the enchantments from the specified NBT list tag (ench or StoredEnchantments) diff --git a/src/WorldStorage/EnchantmentSerializer.h b/src/WorldStorage/EnchantmentSerializer.h index d616b0f62..9ed362900 100644 --- a/src/WorldStorage/EnchantmentSerializer.h +++ b/src/WorldStorage/EnchantmentSerializer.h @@ -1,17 +1,17 @@ #pragma once -#include "Enchantments.h" +class cEnchantments; +class cFastNBTWriter; +class cParsedNBT; -class cEnchantmentSerializer +namespace EnchantmentSerializer { -public: - /// Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") - static void WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName); + void WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName); /// Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) - static void ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx); + void ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx); }; diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 51e1a8d1b..91cc6b06d 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -92,7 +92,7 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; m_Writer.BeginCompound("tag"); - cEnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName); + EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName); m_Writer.EndCompound(); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 702b809fb..25661de76 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -640,7 +640,7 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ int EnchTag = a_NBT.FindChildByName(TagTag, EnchName); if (EnchTag > 0) { - cEnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag); + EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag); } return true; -- cgit v1.2.3 From 3c0e8c8da0e397f3fda6b1565e7b2e9eeb4a747b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 19 Jan 2014 19:31:43 +0100 Subject: Rewritten SocketThreads for proper shutdown scenario. This fixes #560 and #390. --- src/ClientHandle.cpp | 6 +- src/HTTPServer/HTTPConnection.cpp | 2 +- src/OSSupport/Socket.cpp | 19 +++ src/OSSupport/Socket.h | 6 +- src/OSSupport/SocketThreads.cpp | 236 +++++++++++++++++++------------------- src/OSSupport/SocketThreads.h | 79 +++++++------ src/Server.cpp | 11 +- src/Server.h | 8 +- 8 files changed, 189 insertions(+), 178 deletions(-) (limited to 'src') diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index faf583fbb..1eec00bc3 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -120,9 +120,6 @@ cClientHandle::~cClientHandle() LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this); - // Remove from cSocketThreads, we're not to be called anymore: - cRoot::Get()->GetServer()->ClientDestroying(this); - { cCSLock Lock(m_CSChunkLists); m_LoadedChunks.clear(); @@ -160,8 +157,7 @@ cClientHandle::~cClientHandle() cRoot::Get()->GetServer()->WriteToClient(this, Data); } - // Queue the socket to close as soon as it sends all outgoing data: - cRoot::Get()->GetServer()->QueueClientClose(this); + // Close the socket as soon as it sends all outgoing data: cRoot::Get()->GetServer()->RemoveClient(this); delete m_Protocol; diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index a4af706f2..78b7ce4d9 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -26,7 +26,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : cHTTPConnection::~cHTTPConnection() { - // LOGD("HTTP: Del connection at %p", this); + delete m_CurrentRequest; } diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp index 8ea5d8320..d80c9bb3d 100644 --- a/src/OSSupport/Socket.cpp +++ b/src/OSSupport/Socket.cpp @@ -87,6 +87,25 @@ void cSocket::CloseSocket() +void cSocket::ShutdownReadWrite(void) +{ + #ifdef _WIN32 + int res = shutdown(m_Socket, SD_BOTH); + #else + int res = shutdown(m_Socket, SHUT_RDWR); + #endif + if (res != 0) + { + LOGWARN("%s: Error shutting down socket %d (%s): %d (%s)", + __FUNCTION__, m_Socket, m_IPString.c_str(), this->GetLastError(), GetLastErrorString().c_str() + ); + } +} + + + + + AString cSocket::GetErrorString( int a_ErrNo ) { char buffer[ 1024 ]; diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h index b86560de8..91c9ca5fd 100644 --- a/src/OSSupport/Socket.h +++ b/src/OSSupport/Socket.h @@ -39,7 +39,11 @@ public: bool IsValid(void) const { return IsValidSocket(m_Socket); } void CloseSocket(void); - + + /** Notifies the socket that we don't expect any more reads nor writes on it. + Most TCPIP implementations use this to send the FIN flag in a packet */ + void ShutdownReadWrite(void); + operator xSocket(void) const; xSocket GetSocket(void) const; diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp index b222a2e4e..b8069cf00 100644 --- a/src/OSSupport/SocketThreads.cpp +++ b/src/OSSupport/SocketThreads.cpp @@ -132,47 +132,6 @@ void cSocketThreads::Write(const cCallback * a_Client, const AString & a_Data) -/// Stops reading from the socket - when this call returns, no more calls to the callbacks are made -void cSocketThreads::StopReading(const cCallback * a_Client) -{ - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->StopReading(a_Client)) - { - return; - } - } // for itr - m_Threads[] - - // Cannot assert, this normally happens if the socket is closed before the client deinitializes - // ASSERT(!"Stopping reading on an unknown client"); -} - - - - - -/// Queues the socket for closing, as soon as its outgoing data is sent -void cSocketThreads::QueueClose(const cCallback * a_Client) -{ - LOGD("QueueClose(client %p)", a_Client); - - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->QueueClose(a_Client)) - { - return; - } - } // for itr - m_Threads[] - - ASSERT(!"Queueing close of an unknown client"); -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cSocketThreads::cSocketThread: @@ -210,13 +169,13 @@ cSocketThreads::cSocketThread::~cSocketThread() void cSocketThreads::cSocketThread::AddClient(const cSocket & a_Socket, cCallback * a_Client) { + ASSERT(m_Parent->m_CS.IsLockedByCurrentThread()); ASSERT(m_NumSlots < MAX_SLOTS); // Use HasEmptySlot() to check before adding m_Slots[m_NumSlots].m_Client = a_Client; m_Slots[m_NumSlots].m_Socket = a_Socket; m_Slots[m_NumSlots].m_Outgoing.clear(); - m_Slots[m_NumSlots].m_ShouldClose = false; - m_Slots[m_NumSlots].m_ShouldCallClient = true; + m_Slots[m_NumSlots].m_State = sSlot::ssNormal; m_NumSlots++; // Notify the thread of the change: @@ -230,7 +189,7 @@ void cSocketThreads::cSocketThread::AddClient(const cSocket & a_Socket, cCallbac bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client) { - // Returns true if removed, false if not found + ASSERT(m_Parent->m_CS.IsLockedByCurrentThread()); if (m_NumSlots == 0) { @@ -244,8 +203,29 @@ bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client) continue; } - // Found, remove it: - m_Slots[i] = m_Slots[--m_NumSlots]; + // Found the slot: + if (m_Slots[i].m_State == sSlot::ssRemoteClosed) + { + // The remote has already closed the socket, remove the slot altogether: + m_Slots[i] = m_Slots[--m_NumSlots]; + } + else + { + // Query and queue the last batch of outgoing data: + m_Slots[i].m_Client->GetOutgoingData(m_Slots[i].m_Outgoing); + if (m_Slots[i].m_Outgoing.empty()) + { + // No more outgoing data, shut the socket down immediately: + m_Slots[i].m_Socket.ShutdownReadWrite(); + m_Slots[i].m_State = sSlot::ssShuttingDown; + } + else + { + // More data to send, shut down reading and wait for the rest to get sent: + m_Slots[i].m_State = sSlot::ssWritingRestOut; + } + m_Slots[i].m_Client = NULL; + } // Notify the thread of the change: ASSERT(m_ControlSocket2.IsValid()); @@ -263,6 +243,8 @@ bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client) bool cSocketThreads::cSocketThread::HasClient(const cCallback * a_Client) const { + ASSERT(m_Parent->m_CS.IsLockedByCurrentThread()); + for (int i = m_NumSlots - 1; i >= 0; --i) { if (m_Slots[i].m_Client == a_Client) @@ -295,6 +277,8 @@ bool cSocketThreads::cSocketThread::HasSocket(const cSocket * a_Socket) const bool cSocketThreads::cSocketThread::NotifyWrite(const cCallback * a_Client) { + ASSERT(m_Parent->m_CS.IsLockedByCurrentThread()); + if (HasClient(a_Client)) { // Notify the thread that there's another packet in the queue: @@ -311,7 +295,7 @@ bool cSocketThreads::cSocketThread::NotifyWrite(const cCallback * a_Client) bool cSocketThreads::cSocketThread::Write(const cCallback * a_Client, const AString & a_Data) { - // Returns true if socket handled by this thread + ASSERT(m_Parent->m_CS.IsLockedByCurrentThread()); for (int i = m_NumSlots - 1; i >= 0; --i) { if (m_Slots[i].m_Client == a_Client) @@ -332,47 +316,6 @@ bool cSocketThreads::cSocketThread::Write(const cCallback * a_Client, const AStr -bool cSocketThreads::cSocketThread::StopReading (const cCallback * a_Client) -{ - // Returns true if client handled by this thread - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (m_Slots[i].m_Client == a_Client) - { - m_Slots[i].m_ShouldCallClient = false; - return true; - } - } // for i - m_Slots[] - return false; -} - - - - - -bool cSocketThreads::cSocketThread::QueueClose(const cCallback * a_Client) -{ - // Returns true if socket handled by this thread - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (m_Slots[i].m_Client == a_Client) - { - m_Slots[i].m_ShouldClose = true; - - // Notify the thread that there's a close queued (in case its conditions are already met): - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("c", 1); - - return true; - } - } // for i - m_Slots[] - return false; -} - - - - - bool cSocketThreads::cSocketThread::Start(void) { // Create the control socket listener @@ -446,10 +389,13 @@ void cSocketThreads::cSocketThread::Execute(void) fd_set fdRead; cSocket::xSocket Highest = m_ControlSocket1.GetSocket(); - PrepareSet(&fdRead, Highest); + PrepareSet(&fdRead, Highest, false); // Wait for the sockets: - if (select(Highest + 1, &fdRead, NULL, NULL, NULL) == -1) + timeval Timeout; + Timeout.tv_sec = 5; + Timeout.tv_usec = 0; + if (select(Highest + 1, &fdRead, NULL, NULL, &Timeout) == -1) { LOG("select(R) call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str()); continue; @@ -460,8 +406,7 @@ void cSocketThreads::cSocketThread::Execute(void) // Test sockets for writing: fd_set fdWrite; Highest = m_ControlSocket1.GetSocket(); - PrepareSet(&fdWrite, Highest); - timeval Timeout; + PrepareSet(&fdWrite, Highest, true); Timeout.tv_sec = 0; Timeout.tv_usec = 0; if (select(Highest + 1, NULL, &fdWrite, NULL, &Timeout) == -1) @@ -471,6 +416,8 @@ void cSocketThreads::cSocketThread::Execute(void) } WriteToSockets(&fdWrite); + + CleanUpShutSockets(); } // while (!mShouldTerminate) } @@ -478,7 +425,7 @@ void cSocketThreads::cSocketThread::Execute(void) -void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest) +void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest, bool a_IsForWriting) { FD_ZERO(a_Set); FD_SET(m_ControlSocket1.GetSocket(), a_Set); @@ -490,6 +437,11 @@ void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket { continue; } + if (m_Slots[i].m_State == sSlot::ssRemoteClosed) + { + // This socket won't provide nor consume any data anymore, don't put it in the Set + continue; + } cSocket::xSocket s = m_Slots[i].m_Socket.GetSocket(); FD_SET(s, a_Set); if (s > a_Highest) @@ -525,29 +477,42 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read) } char Buffer[1024]; int Received = m_Slots[i].m_Socket.Receive(Buffer, ARRAYCOUNT(Buffer), 0); - if (Received == 0) + if (Received <= 0) { - // The socket has been closed by the remote party, close our socket and let it be removed after we process all reading - m_Slots[i].m_Socket.CloseSocket(); - if (m_Slots[i].m_ShouldCallClient) + // The socket has been closed by the remote party + switch (m_Slots[i].m_State) { - m_Slots[i].m_Client->SocketClosed(); - } - } - else if (Received > 0) - { - if (m_Slots[i].m_ShouldCallClient) - { - m_Slots[i].m_Client->DataReceived(Buffer, Received); - } + case sSlot::ssNormal: + { + // Notify the callback that the remote has closed the socket; keep the slot + m_Slots[i].m_Client->SocketClosed(); + m_Slots[i].m_State = sSlot::ssRemoteClosed; + break; + } + case sSlot::ssWritingRestOut: + case sSlot::ssShuttingDown: + case sSlot::ssShuttingDown2: + { + // Force-close the socket and remove the slot: + m_Slots[i].m_Socket.CloseSocket(); + m_Slots[i] = m_Slots[--m_NumSlots]; + break; + } + default: + { + LOG("%s: Unexpected socket state: %d (%s)", + __FUNCTION__, m_Slots[i].m_Socket.GetSocket(), m_Slots[i].m_Socket.GetIPString().c_str() + ); + ASSERT(!"Unexpected socket state"); + break; + } + } // switch (m_Slots[i].m_State) } else { - // The socket has encountered an error, close it and let it be removed after we process all reading - m_Slots[i].m_Socket.CloseSocket(); - if (m_Slots[i].m_ShouldCallClient) + if (m_Slots[i].m_Client != NULL) { - m_Slots[i].m_Client->SocketClosed(); + m_Slots[i].m_Client->DataReceived(Buffer, Received); } } } // for i - m_Slots[] @@ -571,22 +536,17 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write) if (m_Slots[i].m_Outgoing.empty()) { // Request another chunk of outgoing data: - if (m_Slots[i].m_ShouldCallClient) + if (m_Slots[i].m_Client != NULL) { m_Slots[i].m_Client->GetOutgoingData(m_Slots[i].m_Outgoing); } if (m_Slots[i].m_Outgoing.empty()) { - // Nothing ready - if (m_Slots[i].m_ShouldClose) + // No outgoing data is ready + if (m_Slots[i].m_State == sSlot::ssWritingRestOut) { - // Socket was queued for closing and there's no more data to send, close it now: - - // DEBUG - LOGD("Socket was queued for closing, closing now. Slot %d, client %p, socket %d", i, m_Slots[i].m_Client, m_Slots[i].m_Socket.GetSocket()); - - m_Slots[i].m_Socket.CloseSocket(); - // The slot must be freed actively by the client, using RemoveClient() + m_Slots[i].m_State = sSlot::ssShuttingDown; + m_Slots[i].m_Socket.ShutdownReadWrite(); } continue; } @@ -598,7 +558,7 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write) int Err = cSocket::GetLastError(); LOGWARNING("Error %d while writing to client \"%s\", disconnecting. \"%s\"", Err, m_Slots[i].m_Socket.GetIPString().c_str(), cSocket::GetErrorString(Err).c_str()); m_Slots[i].m_Socket.CloseSocket(); - if (m_Slots[i].m_ShouldCallClient) + if (m_Slots[i].m_Client != NULL) { m_Slots[i].m_Client->SocketClosed(); } @@ -606,6 +566,12 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write) } m_Slots[i].m_Outgoing.erase(0, Sent); + if (m_Slots[i].m_Outgoing.empty() && (m_Slots[i].m_State == sSlot::ssWritingRestOut)) + { + m_Slots[i].m_State = sSlot::ssShuttingDown; + m_Slots[i].m_Socket.ShutdownReadWrite(); + } + // _X: If there's data left, it means the client is not reading fast enough, the server would unnecessarily spin in the main loop with zero actions taken; so signalling is disabled // This means that if there's data left, it will be sent only when there's incoming data or someone queues another packet (for any socket handled by this thread) /* @@ -622,3 +588,31 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write) + +void cSocketThreads::cSocketThread::CleanUpShutSockets(void) +{ + for (int i = m_NumSlots - 1; i >= 0; i--) + { + switch (m_Slots[i].m_State) + { + case sSlot::ssShuttingDown2: + { + // The socket has reached the shutdown timeout, close it and clear its slot: + m_Slots[i].m_Socket.CloseSocket(); + m_Slots[i] = m_Slots[--m_NumSlots]; + break; + } + case sSlot::ssShuttingDown: + { + // The socket has been shut down for a single thread loop, let it loop once more before closing: + m_Slots[i].m_State = sSlot::ssShuttingDown2; + break; + } + default: break; + } + } // for i - m_Slots[] +} + + + + diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h index e16ae69fb..9e1947ab6 100644 --- a/src/OSSupport/SocketThreads.h +++ b/src/OSSupport/SocketThreads.h @@ -7,19 +7,20 @@ /* Additional details: -When a client is terminating a connection: -- they call the StopReading() method to disable callbacks for the incoming data -- they call the Write() method to queue any outstanding outgoing data -- they call the QueueClose() method to queue the socket to close after outgoing data has been sent. -When a socket slot is marked as having no callback, it is kept alive until its outgoing data queue is empty and its m_ShouldClose flag is set. -This means that the socket can be written to several times before finally closing it via QueueClose() +When a client wants to terminate the connection, they call the RemoveClient() function. This calls the +callback one last time to read all the available outgoing data, putting it in the slot's m_OutgoingData +buffer. Then it marks the slot as having no callback. The socket is kept alive until its outgoing data +queue is empty, then shutdown is called on it and finally the socket is closed after a timeout. +If at any time within this the remote end closes the socket, then the socket is closed directly. +As soon as the socket is closed, the slot is finally removed from the SocketThread. +The graph in $/docs/SocketThreads States.gv shows the state-machine transitions of the slot. */ -/// How many clients should one thread handle? (must be less than FD_SETSIZE for your platform) +/** How many clients should one thread handle? (must be less than FD_SETSIZE for your platform) */ #define MAX_SLOTS 63 @@ -27,8 +28,6 @@ This means that the socket can be written to several times before finally closin #pragma once -#ifndef CSOCKETTHREADS_H_INCLUDED -#define CSOCKETTHREADS_H_INCLUDED #include "Socket.h" #include "IsThread.h" @@ -64,13 +63,13 @@ public: // Force a virtual destructor in all subclasses: virtual ~cCallback() {} - /// Called when data is received from the remote party + /** Called when data is received from the remote party */ virtual void DataReceived(const char * a_Data, int a_Size) = 0; - /// Called when data can be sent to remote party; the function is supposed to append outgoing data to a_Data + /** Called when data can be sent to remote party; the function is supposed to *append* outgoing data to a_Data */ virtual void GetOutgoingData(AString & a_Data) = 0; - /// Called when the socket has been closed for any reason + /** Called when the socket has been closed for any reason */ virtual void SocketClosed(void) = 0; } ; @@ -78,26 +77,21 @@ public: cSocketThreads(void); ~cSocketThreads(); - /// Add a (socket, client) pair for processing, data from a_Socket is to be sent to a_Client; returns true if successful + /** Add a (socket, client) pair for processing, data from a_Socket is to be sent to a_Client; returns true if successful */ bool AddClient(const cSocket & a_Socket, cCallback * a_Client); /** Remove the associated socket and the client from processing. - The socket is left to send its data and is removed only after all its m_OutgoingData is sent + The socket is left to send its last outgoing data and is removed only after all its m_Outgoing is sent + and after the socket is properly shutdown (unless the remote disconnects before that) */ void RemoveClient(const cCallback * a_Client); - /// Notify the thread responsible for a_Client that the client has something to write + /** Notify the thread responsible for a_Client that the client has something to write */ void NotifyWrite(const cCallback * a_Client); - /// Puts a_Data into outgoing data queue for a_Client + /** Puts a_Data into outgoing data queue for a_Client */ void Write(const cCallback * a_Client, const AString & a_Data); - /// Stops reading from the client - when this call returns, no more calls to the callbacks are made - void StopReading(const cCallback * a_Client); - - /// Queues the client for closing, as soon as its outgoing data is sent - void QueueClose(const cCallback * a_Client); - private: class cSocketThread : @@ -120,8 +114,6 @@ private: bool HasSocket (const cSocket * a_Socket) const; bool NotifyWrite (const cCallback * a_Client); // Returns true if client handled by this thread bool Write (const cCallback * a_Client, const AString & a_Data); // Returns true if client handled by this thread - bool StopReading (const cCallback * a_Client); // Returns true if client handled by this thread - bool QueueClose (const cCallback * a_Client); // Returns true if client handled by this thread bool Start(void); // Hide the cIsThread's Start method, we need to provide our own startup to create the control socket @@ -135,24 +127,45 @@ private: cSocket m_ControlSocket1; cSocket m_ControlSocket2; - // Socket-client-packetqueues triplets. + // Socket-client-dataqueues-state quadruplets. // Manipulation with these assumes that the parent's m_CS is locked struct sSlot { - cSocket m_Socket; // The socket is primarily owned by this + /** The socket is primarily owned by this object */ + cSocket m_Socket; + + /** The callback to call for events. May be NULL */ cCallback * m_Client; - AString m_Outgoing; // If sending writes only partial data, the rest is stored here for another send - bool m_ShouldClose; // If true, the socket is to be closed after sending all outgoing data - bool m_ShouldCallClient; // If true, the client callbacks are called. Set to false in StopReading() + + /** If sending writes only partial data, the rest is stored here for another send. + Also used when the slot is being removed to store the last batch of outgoing data. */ + AString m_Outgoing; + + enum eState + { + ssNormal, ///< Normal read / write operations + ssWritingRestOut, ///< The client callback was removed, continue to send outgoing data + ssShuttingDown, ///< The last outgoing data has been sent, the socket has called shutdown() + ssShuttingDown2, ///< The shutdown has been done at least 1 thread loop ago (timeout detection) + ssRemoteClosed, ///< The remote end has closed the connection (and we still have a client callback) + } m_State; } ; + sSlot m_Slots[MAX_SLOTS]; int m_NumSlots; // Number of slots actually used virtual void Execute(void) override; - void PrepareSet (fd_set * a_Set, cSocket::xSocket & a_Highest); // Puts all sockets into the set, along with m_ControlSocket1 + /** Puts all sockets into the set, along with m_ControlSocket1. + Only sockets that are able to send and receive data are put in the Set. + Is a_IsForWriting is true, the ssWritingRestOut sockets are added as well. */ + void PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest, bool a_IsForWriting); + void ReadFromSockets(fd_set * a_Read); // Reads from sockets indicated in a_Read void WriteToSockets (fd_set * a_Write); // Writes to sockets indicated in a_Write + + /** Removes those slots in ssShuttingDown2 state, sets those with ssShuttingDown state to ssShuttingDown2 */ + void CleanUpShutSockets(void); } ; typedef std::list cSocketThreadList; @@ -165,9 +178,3 @@ private: - -#endif // CSOCKETTHREADS_H_INCLUDED - - - - diff --git a/src/Server.cpp b/src/Server.cpp index 5280270b9..4d551e164 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -118,7 +118,7 @@ cServer::cServer(void) : void cServer::ClientDestroying(const cClientHandle * a_Client) { - m_SocketThreads.StopReading(a_Client); + m_SocketThreads.RemoveClient(a_Client); } @@ -143,15 +143,6 @@ void cServer::WriteToClient(const cClientHandle * a_Client, const AString & a_Da -void cServer::QueueClientClose(const cClientHandle * a_Client) -{ - m_SocketThreads.QueueClose(a_Client); -} - - - - - void cServer::RemoveClient(const cClientHandle * a_Client) { m_SocketThreads.RemoveClient(a_Client); diff --git a/src/Server.h b/src/Server.h index 703a7077e..bb55e81b6 100644 --- a/src/Server.h +++ b/src/Server.h @@ -88,14 +88,14 @@ public: // tolua_export const AString & GetServerID(void) const { return m_ServerID; } // tolua_export - void ClientDestroying(const cClientHandle * a_Client); // Called by cClientHandle::Destroy(); stop m_SocketThreads from calling back into a_Client + /** Called by cClientHandle's destructor; stop m_SocketThreads from calling back into a_Client */ + void ClientDestroying(const cClientHandle * a_Client); - void NotifyClientWrite(const cClientHandle * a_Client); // Notifies m_SocketThreads that client has something to be written + /** Notifies m_SocketThreads that client has something to be written */ + void NotifyClientWrite(const cClientHandle * a_Client); void WriteToClient(const cClientHandle * a_Client, const AString & a_Data); // Queues outgoing data for the client through m_SocketThreads - void QueueClientClose(const cClientHandle * a_Client); // Queues the clienthandle to close when all its outgoing data is sent - void RemoveClient(const cClientHandle * a_Client); // Removes the clienthandle from m_SocketThreads /// Don't tick a_Client anymore, it will be ticked from its cPlayer instead -- cgit v1.2.3 From e4c3d799ffddb93c658062f9663ec027fc2f1d5a Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 19 Jan 2014 19:42:25 +0000 Subject: Removed unneeded paramters --- src/BlockEntities/CommandBlockEntity.cpp | 2 +- src/ClientHandle.cpp | 4 ++-- src/ClientHandle.h | 2 +- src/Protocol/Protocol.h | 2 +- src/Protocol/Protocol125.h | 2 +- src/Protocol/Protocol17x.cpp | 18 +++++++++++++----- src/Protocol/Protocol17x.h | 2 +- src/Protocol/ProtocolRecognizer.cpp | 4 ++-- src/Protocol/ProtocolRecognizer.h | 2 +- 9 files changed, 23 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 38737d619..7e9015d33 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -142,7 +142,7 @@ bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk) void cCommandBlockEntity::SendTo(cClientHandle & a_Client) { - a_Client.SendUpdateBlockEntity(GetPosX(), GetPosY(), GetPosZ(), 2, *this); + a_Client.SendUpdateBlockEntity(*this); } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 327fc0358..ec71f8fe8 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -2213,9 +2213,9 @@ void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -void cClientHandle::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) +void cClientHandle::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { - m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_BlockEntity); + m_Protocol->SendUpdateBlockEntity(a_BlockEntity); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index daa185ca0..4add022a6 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -136,7 +136,7 @@ public: void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay); void SendUnloadChunk (int a_ChunkX, int a_ChunkZ); - void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity); + void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity); void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); void SendWeather (eWeather a_Weather); diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index ac925e382..1bc5d528e 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -103,7 +103,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) = 0; + virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0; virtual void SendWeather (eWeather a_Weather) = 0; diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index ec72ddd01..310f9dd78 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -79,7 +79,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) override {}; + virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override {}; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index c85641ca8..293f96186 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -893,13 +893,21 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -void cProtocol172::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) +void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { cPacketizer Pkt(*this, 0x35); // Update tile entity packet - Pkt.WriteInt(a_BlockX); - Pkt.WriteShort(a_BlockY); - Pkt.WriteInt(a_BlockZ); - Pkt.WriteByte(a_Action); + Pkt.WriteInt(a_BlockEntity.GetPosX()); + Pkt.WriteShort(a_BlockEntity.GetPosY()); + Pkt.WriteInt(a_BlockEntity.GetPosZ()); + + Byte Action = 0; + switch (a_BlockEntity.GetBlockType()) + { + case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing + case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text + default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; + } + Pkt.WriteByte(Action); Pkt.WriteBlockEntity(a_BlockEntity); } diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index b1d902507..3ae774c18 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -102,7 +102,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) override; + virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 86f46f02f..5524af136 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -636,10 +636,10 @@ void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -void cProtocolRecognizer::SendUpdateBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) +void cProtocolRecognizer::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { ASSERT(m_Protocol != NULL); - m_Protocol->SendUpdateBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Action, a_BlockEntity); + m_Protocol->SendUpdateBlockEntity(a_BlockEntity); } diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index c1c8abdd5..2dccace6e 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -114,7 +114,7 @@ public: virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Action, cBlockEntity & a_BlockEntity) override; + virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; -- cgit v1.2.3 From 4a01879911c5673612693531c4f8970c1644947b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 19 Jan 2014 23:45:26 +0100 Subject: cLuaState can now check function params. --- src/Bindings/LuaState.cpp | 34 ++++++++++++++++++++++++++++++++++ src/Bindings/LuaState.h | 3 +++ 2 files changed, 37 insertions(+) (limited to 'src') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 00e62fcf6..bfee1d037 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -914,6 +914,40 @@ bool cLuaState::CheckParamString(int a_StartParam, int a_EndParam) +bool cLuaState::CheckParamFunction(int a_StartParam, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (lua_isfunction(m_LuaState, i)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("Error in function '%s' parameter #%d. Function expected, got %s", + (entry.name != NULL) ? entry.name : "?", i, GetTypeText(i).c_str() + ); + LogStackTrace(); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + bool cLuaState::CheckParamEnd(int a_Param) { tolua_Error tolua_err; diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 414e5e4b2..f8b67f5cd 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -815,6 +815,9 @@ public: /// Returns true if the specified parameters on the stack are strings; also logs warning if not bool CheckParamString(int a_StartParam, int a_EndParam = -1); + /// Returns true if the specified parameters on the stack are functions; also logs warning if not + bool CheckParamFunction(int a_StartParam, int a_EndParam = -1); + /// Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) bool CheckParamEnd(int a_Param); -- cgit v1.2.3 From 41618bf242e66744431a1d28e0409f543fb240e4 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 19 Jan 2014 23:49:19 +0100 Subject: Changed the cWorld::ScheduleTask() signature. Now it takes the delay in ticks as an argument, and a cTask descendant as the task to run. Lua API has been updated similarly. --- src/Bindings/ManualBindings.cpp | 24 ++-- src/World.cpp | 32 +++-- src/World.h | 276 +++++++++++++++++++++------------------- 3 files changed, 181 insertions(+), 151 deletions(-) (limited to 'src') diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 3ebe7b294..2206dd371 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -986,11 +986,10 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) class cLuaScheduledWorldTask : - public cWorld::cScheduledTask + public cWorld::cTask { public: - cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef, int a_Ticks) : - cScheduledTask(a_Ticks), + cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : m_Plugin(a_Plugin), m_FnRef(a_FnRef) { @@ -1025,14 +1024,19 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) } // Retrieve the args: - cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, 0); - if (self == NULL) + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber (2) || + !L.CheckParamFunction(3) + ) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); + return 0; } - if (!lua_isfunction(tolua_S, 2)) + cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL); + if (World == NULL) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1"); + return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); } // Create a reference to the function: @@ -1042,9 +1046,9 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } - int Ticks = (int) tolua_tonumber (tolua_S, 3, 0); + int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0); - self->ScheduleTask(new cLuaScheduledWorldTask(*Plugin, FnRef, Ticks)); + World->ScheduleTask(DelayTicks, new cLuaScheduledWorldTask(*Plugin, FnRef)); return 0; } diff --git a/src/World.cpp b/src/World.cpp index 6520702c7..5e9f4a38a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -865,13 +865,17 @@ void cWorld::TickQueuedTasks(void) } // for itr - m_Tasks[] } -void cWorld::TickScheduledTasks() + + + + +void cWorld::TickScheduledTasks(void) { - ScheduledTaskList Tasks; // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks + cScheduledTasks Tasks; { cCSLock Lock(m_CSScheduledTasks); - while (!m_ScheduledTasks.empty() && m_ScheduledTasks.front()->Ticks < m_WorldAge) + while (!m_ScheduledTasks.empty() && (m_ScheduledTasks.front()->m_TargetTick < m_WorldAge)) { Tasks.push_back(m_ScheduledTasks.front()); m_ScheduledTasks.pop_front(); @@ -879,9 +883,9 @@ void cWorld::TickScheduledTasks() } // Execute and delete each task: - for (ScheduledTaskList::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) + for (cScheduledTasks::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) { - (*itr)->Run(*this); + (*itr)->m_Task->Run(*this); delete *itr; } // for itr - m_Tasks[] } @@ -2627,19 +2631,25 @@ void cWorld::QueueTask(cTask * a_Task) m_Tasks.push_back(a_Task); } -void cWorld::ScheduleTask(cScheduledTask * a_Task) + + + + +void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task) { - a_Task->Ticks = a_Task->Ticks + m_WorldAge; + Int64 TargetTick = a_DelayTicks + m_WorldAge; + + // Insert the task into the list of scheduled tasks, ordered by its target tick cCSLock Lock(m_CSScheduledTasks); - for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++) + for (cScheduledTasks::iterator itr = m_ScheduledTasks.begin(), end = m_ScheduledTasks.end(); itr != end; ++itr) { - if((*itr)->Ticks >= a_Task->Ticks) + if ((*itr)->m_TargetTick >= TargetTick) { - m_ScheduledTasks.insert(itr, a_Task); + m_ScheduledTasks.insert(itr, new cScheduledTask(TargetTick, a_Task)); return; } } - m_ScheduledTasks.push_back(a_Task); + m_ScheduledTasks.push_back(new cScheduledTask(TargetTick, a_Task)); } diff --git a/src/World.h b/src/World.h index 1a7ad0cb1..930d9d421 100644 --- a/src/World.h +++ b/src/World.h @@ -66,7 +66,7 @@ public: // tolua_end - /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor + /** A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor */ class cLock : public cCSLock { @@ -74,8 +74,9 @@ public: public: cLock(cWorld & a_World); } ; + - /// A common ancestor for all tasks queued onto the tick thread + /** A common ancestor for all tasks queued onto the tick thread */ class cTask { public: @@ -83,18 +84,8 @@ public: virtual void Run(cWorld & a_World) = 0; } ; - /// A common ancestor for all scheduled tasks queued onto the tick thread - class cScheduledTask - { - public: - cScheduledTask(const int a_Ticks) : Ticks(a_Ticks) {}; - virtual ~cScheduledTask() {}; - virtual void Run(cWorld & a_World) = 0; - int Ticks; - }; - typedef std::vector cTasks; - typedef std::list ScheduledTaskList; + class cTaskSaveAllChunks : public cTask @@ -128,16 +119,16 @@ public: BroadcastTimeUpdate(); } - /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable + /** Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */ eGameMode GetGameMode(void) const { return m_GameMode; } - /// Returns true if the world is in Creative mode + /** Returns true if the world is in Creative mode */ bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); } - /// Returns true if the world is in Survival mode + /** Returns true if the world is in Survival mode */ bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); } - /// Returns true if the world is in Adventure mode + /** Returns true if the world is in Adventure mode */ bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); } bool IsPVPEnabled(void) const { return m_bEnabledPVP; } @@ -147,12 +138,12 @@ public: eDimension GetDimension(void) const { return m_Dimension; } - /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated + /** Returns the world height at the specified coords; waits for the chunk to get loaded / generated */ int GetHeight(int a_BlockX, int a_BlockZ); // tolua_end - /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated + /** Retrieves the world height at the specified coords; returns false if chunk not loaded / generated */ bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp // Broadcast respective packets to all clients of the chunk where the event is taking place @@ -187,7 +178,7 @@ public: void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL); - /// If there is a block entity at the specified coords, sends it to the client specified + /** If there is a block entity at the specified coords, sends it to the client specified */ void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); @@ -221,7 +212,7 @@ public: bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); - /// Gets the chunk's blocks, only the block types + /** Gets the chunk's blocks, only the block types */ bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const; @@ -234,13 +225,13 @@ public: void AddPlayer( cPlayer* a_Player ); void RemovePlayer( cPlayer* a_Player ); - /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true - bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored - bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << + /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ + bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << + + /** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored */ + bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - /// Finds a player from a partial or complete player name and calls the callback - case-insensitive + /** Finds a player from a partial or complete player name and calls the callback - case-insensitive */ bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) @@ -248,74 +239,74 @@ public: void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player - /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr + /** Adds the entity into its appropriate chunk; takes ownership of the entity ptr */ void AddEntity(cEntity * a_Entity); bool HasEntity(int a_UniqueID); - /// Removes the entity, the entity ptr ownership is assumed taken by the caller + /** Removes the entity, the entity ptr ownership is assumed taken by the caller */ void RemoveEntity(cEntity * a_Entity); - /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true + /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true + /** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. + /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */ bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Compares clients of two chunks, calls the callback accordingly + /** Compares clients of two chunks, calls the callback accordingly */ void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); - /// Adds client to a chunk, if not already present; returns true if added, false if present + /** Adds client to a chunk, if not already present; returns true if added, false if present */ bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - /// Removes client from the chunk specified + /** Removes client from the chunk specified */ void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - /// Removes the client from all chunks it is present in + /** Removes the client from all chunks it is present in */ void RemoveClientFromChunks(cClientHandle * a_Client); - /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) + /** Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) */ void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - /// Removes client from ChunkSender's queue of chunks to be sent + /** Removes client from ChunkSender's queue of chunks to be sent */ void RemoveClientFromChunkSender(cClientHandle * a_Client); - /// Touches the chunk, causing it to be loaded or generated + /** Touches the chunk, causing it to be loaded or generated */ void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) + /** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */ bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() + /** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */ void LoadChunks(const cChunkCoordsList & a_Chunks); - /// Marks the chunk as failed-to-load: + /** Marks the chunk as failed-to-load: */ void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() + /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() */ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines() + /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines() */ bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! + /** Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! */ void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true); - /// Regenerate the given chunk: + /** Regenerate the given chunk: */ void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - /// Generates the given chunk, if not already generated + /** Generates the given chunk, if not already generated */ void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted + /** Queues a chunk for lighting; a_Callback is called after the chunk is lighted */ void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL); bool IsChunkLighted(int a_ChunkX, int a_ChunkZ); - /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully + /** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */ bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback); // tolua_begin @@ -366,30 +357,30 @@ public: // tolua_begin - /// Spawns item pickups for each item in the list. May compress pickups if too many entities: + /** Spawns item pickups for each item in the list. May compress pickups if too many entities: */ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false); - /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: + /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false); - /// Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. + /** Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. */ int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta); - /// Spawns an minecart at the given coordinates. + /** Spawns an minecart at the given coordinates. */ int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1); - /// Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. + /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */ int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward); - /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided + /** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1); // tolua_end - /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType + /** Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType */ void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType); - /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. + /** Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. */ bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure); // tolua_begin @@ -400,10 +391,10 @@ public: double GetSpawnY(void) const { return m_SpawnY; } double GetSpawnZ(void) const { return m_SpawnZ; } - /// Wakes up the simulators for the specified block + /** Wakes up the simulators for the specified block */ void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); - /// Wakes up the simulators for the specified area of blocks + /** Wakes up the simulators for the specified area of blocks */ void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ); // tolua_end @@ -414,22 +405,22 @@ public: inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } inline cRedstoneSimulator * GetRedstoneSimulator(void) { return m_RedstoneSimulator; } - /// Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true + /** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */ bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true + /** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */ bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true + /** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */ bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); - /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true + /** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */ bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback); - /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true + /** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */ bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback); - /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true + /** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */ bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp /** Does an explosion with the specified strength at the specified coordinate @@ -447,71 +438,71 @@ public: */ void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export - /// Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found + /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found + /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */ bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found + /** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */ bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found + /** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */ bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found + /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */ bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found + /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */ bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp - /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found + /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp - /// a_Player is using block entity at [x, y, z], handle that: + /** a_Player is using block entity at [x, y, z], handle that: */ void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); } // tolua_export - /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback + /** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */ bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback); void GrowTreeImage(const sSetBlockVector & a_Blocks); // tolua_begin - /// Grows a tree at the specified coords, either from a sapling there, or based on the biome + /** Grows a tree at the specified coords, either from a sapling there, or based on the biome */ void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); - /// Grows a tree at the specified coords, based on the sapling meta provided + /** Grows a tree at the specified coords, based on the sapling meta provided */ void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_SaplingMeta); - /// Grows a tree at the specified coords, based on the biome in the place + /** Grows a tree at the specified coords, based on the biome in the place */ void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); - /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini + /** Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini */ bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false); - /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config + /** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config */ void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem) + /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem) */ void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); - /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config + /** Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config */ void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - /// Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value + /** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */ int GetBiomeAt(int a_BlockX, int a_BlockZ); - /// Returns the name of the world + /** Returns the name of the world */ const AString & GetName(void) const { return m_WorldName; } - /// Returns the name of the world.ini file used by this world + /** Returns the name of the world.ini file used by this world */ const AString & GetIniFileName(void) const {return m_IniFileName; } // tolua_end @@ -543,22 +534,23 @@ public: if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--; } - /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead + /** Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead */ void SaveAllChunks(void); - /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources + /** Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources */ void QueueSaveAllChunks(void); // tolua_export - /// Queues a task onto the tick thread. The task object will be deleted once the task is finished + /** Queues a task onto the tick thread. The task object will be deleted once the task is finished */ void QueueTask(cTask * a_Task); // Exported in ManualBindings.cpp - // Queues a task onto the tick thread. The task object will be deleted once the task is finished - void ScheduleTask(cScheduledTask * a_Task); + /** Queues a task onto the tick thread, with the specified delay. + The task object will be deleted once the task is finished */ + void ScheduleTask(int a_DelayTicks, cTask * a_Task); - /// Returns the number of chunks loaded + /** Returns the number of chunks loaded */ int GetNumChunks() const; // tolua_export - /// Returns the number of chunks loaded and dirty, and in the lighting queue + /** Returns the number of chunks loaded and dirty, and in the lighting queue */ void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue); // Various queues length queries (cannot be const, they lock their CS): @@ -569,13 +561,13 @@ public: void InitializeSpawn(void); - /// Starts threads that belong to this world + /** Starts threads that belong to this world */ void Start(void); - /// Stops threads that belong to this world (part of deinit) + /** Stops threads that belong to this world (part of deinit) */ void Stop(void); - /// Processes the blocks queued for ticking with a delay (m_BlockTickQueue[]) + /** Processes the blocks queued for ticking with a delay (m_BlockTickQueue[]) */ void TickQueuedBlocks(void); struct BlockTickQueueItem @@ -586,27 +578,27 @@ public: int TicksToWait; }; - /// Queues the block to be ticked after the specified number of game ticks + /** Queues the block to be ticked after the specified number of game ticks */ void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, int a_TicksToWait); // tolua_export // tolua_begin - /// Casts a thunderbolt at the specified coords + /** Casts a thunderbolt at the specified coords */ void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ); - /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change + /** Sets the specified weather; resets weather interval; asks and notifies plugins of the change */ void SetWeather (eWeather a_NewWeather); - /// Forces a weather change in the next game tick + /** Forces a weather change in the next game tick */ void ChangeWeather (void); - /// Returns the current weather. Instead of comparing values directly to the weather constants, use IsWeatherXXX() functions, if possible + /** Returns the current weather. Instead of comparing values directly to the weather constants, use IsWeatherXXX() functions, if possible */ eWeather GetWeather (void) const { return m_Weather; }; bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } bool IsWeatherRain (void) const { return (m_Weather == wRain); } bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } - /// Returns true if the current weather has any precipitation - rain or storm + /** Returns true if the current weather has any precipitation - rain or storm */ bool IsWeatherWet (void) const { return (m_Weather != wSunny); } // tolua_end @@ -615,7 +607,7 @@ public: cWorldStorage & GetStorage (void) { return m_Storage; } cChunkMap * GetChunkMap (void) { return m_ChunkMap; } - /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call + /** Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call */ void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export @@ -623,20 +615,20 @@ public: bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise + /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export int SpawnMobFinalize(cMonster* a_Monster); - /// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise + /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export - /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! + /** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */ int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } - /// Appends all usernames starting with a_Text (case-insensitive) into Results + /** Appends all usernames starting with a_Text (case-insensitive) into Results */ void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results); - /// Get the current darkness level based on the time + /** Get the current darkness level based on the time */ NIBBLETYPE GetSkyDarkness() { return m_SkyDarkness; } private: @@ -679,18 +671,41 @@ private: } ; + /** A container for tasks that have been scheduled for a specific game tick */ + class cScheduledTask + { + public: + Int64 m_TargetTick; + cTask * m_Task; + + /** Creates a new scheduled task; takes ownership of the task object passed to it. */ + cScheduledTask(Int64 a_TargetTick, cTask * a_Task) : + m_TargetTick(a_TargetTick), + m_Task(a_Task) + { + } + + virtual ~cScheduledTask() + { + delete m_Task; + } + }; + + typedef std::list cScheduledTasks; + + AString m_WorldName; AString m_IniFileName; - /// Name of the storage schema used to load and save chunks + /** Name of the storage schema used to load and save chunks */ AString m_StorageSchema; int m_StorageCompressionFactor; - /// The dimension of the world, used by the client to provide correct lighting scheme + /** The dimension of the world, used by the client to provide correct lighting scheme */ eDimension m_Dimension; - /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe) + /** This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe) */ MTRand m_TickRand; bool m_IsSpawnExplicitlySet; @@ -765,29 +780,30 @@ private: cLightingThread m_Lighting; cTickThread m_TickThread; - /// Guards the m_Tasks + /** Guards the m_Tasks */ cCriticalSection m_CSTasks; - /// Guards the m_ScheduledTasks - cCriticalSection m_CSScheduledTasks; - - /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks + /** Tasks that have been queued onto the tick thread; guarded by m_CSTasks */ cTasks m_Tasks; - /// Tasks that have been queued to be executed on the tick thread at some number of ticks in - /// the future; guarded by m_CSScheduledTasks - ScheduledTaskList m_ScheduledTasks; + /** Guards the m_ScheduledTasks */ + cCriticalSection m_CSScheduledTasks; + + /** Tasks that have been queued to be executed on the tick thread at target tick in the future. + Ordered by increasing m_TargetTick. + Guarded by m_CSScheduledTasks */ + cScheduledTasks m_ScheduledTasks; - /// Guards m_Clients + /** Guards m_Clients */ cCriticalSection m_CSClients; - /// List of clients in this world, these will be ticked by this world + /** List of clients in this world, these will be ticked by this world */ cClientHandleList m_Clients; - /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them + /** Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them */ cClientHandleList m_ClientsToRemove; - /// Clients that are scheduled for adding, waiting for TickClients to add them + /** Clients that are scheduled for adding, waiting for TickClients to add them */ cClientHandleList m_ClientsToAdd; @@ -796,27 +812,27 @@ private: void Tick(float a_Dt, int a_LastTickDurationMSec); - /// Handles the weather in each tick + /** Handles the weather in each tick */ void TickWeather(float a_Dt); - /// Handles the mob spawning/moving/destroying each tick + /** Handles the mob spawning/moving/destroying each tick */ void TickMobs(float a_Dt); - /// Executes all tasks queued onto the tick thread + /** Executes all tasks queued onto the tick thread */ void TickQueuedTasks(void); - /// Executes all tasks queued onto the tick thread + /** Executes all tasks queued onto the tick thread */ void TickScheduledTasks(void); - /// Ticks all clients that are in this world + /** Ticks all clients that are in this world */ void TickClients(float a_Dt); void UpdateSkyDarkness(void); - /// Generates a random spawnpoint on solid land by walking chunks and finding their biomes + /** Generates a random spawnpoint on solid land by walking chunks and finding their biomes */ void GenerateRandomSpawn(void); - /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) + /** Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) */ cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); }; // tolua_export -- cgit v1.2.3 From 9c93ab15ab6ea4131de5af275fdc759bb49ec648 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Mon, 20 Jan 2014 19:02:37 +0000 Subject: Fix a crash but somewhere... --- src/Protocol/Protocol17x.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index e5a380f8a..fefcb9396 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1,4 +1,3 @@ - // Protocol17x.cpp /* @@ -124,7 +123,7 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { cPacketizer Pkt(*this, 0x25); // Block Break Animation packet - Pkt.WriteInt(a_EntityID); + Pkt.WriteVarInt(a_EntityID); Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockY); Pkt.WriteInt(a_BlockZ); -- cgit v1.2.3