diff options
Diffstat (limited to 'src')
37 files changed, 844 insertions, 187 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 2d0300ebf..f65aed9bb 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -31,6 +31,7 @@ $cfile "../Defines.h" $cfile "../ChatColor.h" $cfile "../ClientHandle.h" $cfile "../Entities/Entity.h" +$cfile "../Entities/Floater.h" $cfile "../Entities/Pawn.h" $cfile "../Entities/Player.h" $cfile "../Entities/Pickup.h" diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index ebee2d697..3ebe7b294 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -14,6 +14,7 @@ #include "../WebAdmin.h" #include "../ClientHandle.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -2265,16 +2266,17 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); - tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); - tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); - tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); - tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); - tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); - tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); - tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); - tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); + tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); + tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); + tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); + tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); + tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); + tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); + tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); + tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>); + tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index 5d7e4a37a..97b5c1a66 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "BlockEntity.h" #include "ChestEntity.h" +#include "CommandBlockEntity.h" #include "DispenserEntity.h" #include "DropperEntity.h" #include "EnderChestEntity.h" @@ -23,17 +24,18 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE { switch (a_BlockType) { - case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); - case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); - case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); + case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); + case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); } LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)", __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str() diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp new file mode 100644 index 000000000..ca617b04d --- /dev/null +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -0,0 +1,197 @@ + +// CommandBlockEntity.cpp + +// Implements the cCommandBlockEntity class representing a single command block in the world + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "json/json.h" +#include "CommandBlockEntity.h" +#include "../Entities/Player.h" + +#include "../CommandOutput.h" +#include "../Root.h" +#include "../Server.h" // ExecuteConsoleCommand() + + + + + +cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) : + super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World), + m_ShouldExecute(false), + m_IsPowered(false) +{} + + + + + + +void cCommandBlockEntity::UsedBy(cPlayer * a_Player) +{ + // Nothing to do + UNUSED(a_Player); +} + + + + + +void cCommandBlockEntity::SetCommand(const AString & a_Cmd) +{ + m_Command = a_Cmd; +} + + + + + +void cCommandBlockEntity::SetLastOutput(const AString & a_LastOut) +{ + m_LastOutput = a_LastOut; +} + + + + + +void cCommandBlockEntity::SetResult(const NIBBLETYPE a_Result) +{ + m_Result = a_Result; +} + + + + + +const AString & cCommandBlockEntity::GetCommand(void) const +{ + return m_Command; +} + + + + + +const AString & cCommandBlockEntity::GetLastOutput(void) const +{ + return m_LastOutput; +} + + + + + +NIBBLETYPE cCommandBlockEntity::GetResult(void) const +{ + return m_Result; +} + + + + + +void cCommandBlockEntity::Activate(void) +{ + m_ShouldExecute = true; +} + + + + + +void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered) +{ + if (a_IsPowered && !m_IsPowered) + { + Activate(); + } + m_IsPowered = a_IsPowered; +} + + + + + +bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + if (!m_ShouldExecute) + { + return false; + } + + m_ShouldExecute = false; + Execute(); + return true; +} + + + + + +void cCommandBlockEntity::SendTo(cClientHandle & a_Client) +{ + // Nothing needs to be sent + UNUSED(a_Client); +} + + + + + +bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value) +{ + m_Command = a_Value.get("Command", "").asString(); + + m_LastOutput = a_Value.get("LastOutput", "").asString(); + + return true; +} + + + + + +void cCommandBlockEntity::SaveToJson(Json::Value & a_Value) +{ + a_Value["Command"] = m_Command; + + a_Value["LastOutput"] = m_LastOutput; +} + + + + + +void cCommandBlockEntity::Execute() +{ + class CommandBlockOutCb : + public cCommandOutputCallback + { + cCommandBlockEntity* m_CmdBlock; + + public: + CommandBlockOutCb(cCommandBlockEntity* a_CmdBlock) : m_CmdBlock(a_CmdBlock) {} + + virtual void Out(const AString & a_Text) + { + ASSERT(m_CmdBlock != NULL); + + // Overwrite field + m_CmdBlock->SetLastOutput(a_Text); + } + } CmdBlockOutCb(this); + + LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); + + cServer* Server = cRoot::Get()->GetServer(); + + Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb); + + // TODO 2014-01-18 xdot: Update the signal strength. + m_Result = 0; +} + + + + diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h new file mode 100644 index 000000000..12157670f --- /dev/null +++ b/src/BlockEntities/CommandBlockEntity.h @@ -0,0 +1,91 @@ + +// CommandBlockEntity.h + +// Declares the cCommandBlockEntity class representing a single command block in the world + + + + + +#pragma once + +#include "BlockEntity.h" + + + + + +namespace Json +{ + class Value; +} + + + + + +// tolua_begin + +class cCommandBlockEntity : + public cBlockEntity +{ + typedef cBlockEntity super; + +public: + + // tolua_end + + /// Creates a new empty command block entity + cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); + + bool LoadFromJson( const Json::Value& a_Value ); + virtual void SaveToJson(Json::Value& a_Value ) override; + + virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual void UsedBy(cPlayer * a_Player) override; + + void SetLastOutput(const AString & a_LastOut); + + void SetResult(const NIBBLETYPE a_Result); + + // tolua_begin + + /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate + void SetRedstonePower(bool a_IsPowered); + + /// Sets the command block to execute a command in the next tick + void Activate(void); + + /// Sets the command + void SetCommand(const AString & a_Cmd); + + /// Retrieves stored command + const AString & GetCommand(void) const; + + /// Retrieves the last line of output generated by the command block + const AString & GetLastOutput(void) const; + + /// Retrieves the result (signal strength) of the last operation + NIBBLETYPE GetResult(void) const; + + // tolua_end + +private: + + /// Executes the associated command + void Execute(); + + bool m_ShouldExecute; + bool m_IsPowered; + + AString m_Command; + + AString m_LastOutput; + + NIBBLETYPE m_Result; +} ; // tolua_export + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b3af6aedd..275099540 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,10 +2,6 @@ cmake_minimum_required (VERSION 2.8.2) project (MCServer) -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03") -endif() - include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/") include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include") diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 0735c8144..a72464ec3 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1298,6 +1298,7 @@ void cChunk::CreateBlockEntities(void) switch (BlockType) { case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_ENDER_CHEST: @@ -1425,6 +1426,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, switch (a_BlockType) { case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_ENDER_CHEST: @@ -2268,6 +2270,38 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl +bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) + { + continue; + } + if ((*itr)->GetBlockType() != E_BLOCK_COMMAND_BLOCK) + { + // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out + return false; + } + + // The correct block entity is here, + if (a_Callback.Item((cCommandBlockEntity *)*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + + bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index f0a50c3c4..4ac38c46c 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -40,12 +40,13 @@ class cFluidSimulatorData; class cMobCensus; class cMobSpawner; -typedef std::list<cClientHandle *> cClientHandleList; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef std::list<cClientHandle *> cClientHandleList; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; @@ -237,6 +238,9 @@ public: /// 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); + /// 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); + /// 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); // Lua-accessible diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index e14090b18..5797eb453 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1968,6 +1968,23 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot +bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback) +{ + int ChunkX, ChunkZ; + int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; + cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return false; + } + return Chunk->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { diff --git a/src/ChunkMap.h b/src/ChunkMap.h index e688d1f93..e9d8ee30b 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -23,6 +23,7 @@ class cDropperEntity; class cDropSpenserEntity; class cFurnaceEntity; class cNoteEntity; +class cCommandBlockEntity; class cPawn; class cPickup; class cChunkDataSerializer; @@ -32,15 +33,16 @@ class cMobSpawner; typedef std::list<cClientHandle *> cClientHandleList; typedef cChunk * cChunkPtr; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cBlockEntity> cBlockEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cDropperEntity> cDropperCallback; -typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; -typedef cItemCallback<cChunk> cChunkCallback; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cBlockEntity> cBlockEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cDropperEntity> cDropperCallback; +typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; +typedef cItemCallback<cChunk> cChunkCallback; @@ -236,6 +238,9 @@ public: /// 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); // Lua-accessible + /// 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); // Lua-accessible + /// 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); // Lua-accessible diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index c8513d516..faf583fbb 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -8,6 +8,7 @@ #include "Entities/Player.h" #include "Inventory.h" #include "BlockEntities/ChestEntity.h" +#include "BlockEntities/CommandBlockEntity.h" #include "BlockEntities/SignEntity.h" #include "UI/Window.h" #include "Item.h" @@ -545,6 +546,15 @@ 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 + { + const char* Data = a_Message.c_str(); + + HandleCommandBlockMessage(Data, a_Message.size()); + + return; + } + cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message); } @@ -552,6 +562,67 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString +void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length) +{ + if (a_Length < 14) + { + LOGD("Malformed MC|AdvCdm packet."); + return; + } + + cByteBuffer Buffer(a_Length); + Buffer.Write(a_Data, a_Length); + + int BlockX, BlockY, BlockZ; + + AString Command; + + char Mode; + + Buffer.ReadChar(Mode); + + switch (Mode) + { + case 0x00: + { + Buffer.ReadBEInt(BlockX); + Buffer.ReadBEInt(BlockY); + Buffer.ReadBEInt(BlockZ); + + Buffer.ReadVarUTF8String(Command); + break; + } + + default: + { + LOGD("Unhandled MC|AdvCdm packet mode."); + return; + } + } + + class cUpdateCommandBlock : + public cCommandBlockCallback + { + AString m_Command; + public: + cUpdateCommandBlock(const AString & a_Command) : m_Command(a_Command) {} + + virtual bool Item(cCommandBlockEntity * a_CommandBlock) override + { + a_CommandBlock->SetCommand(m_Command); + return false; + } + } CmdBlockCB (Command); + + cWorld * World = m_Player->GetWorld(); + + World->DoWithCommandBlockAt(BlockX, BlockY, BlockZ, CmdBlockCB); +} + + + + + void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", diff --git a/src/ClientHandle.h b/src/ClientHandle.h index da2704b72..373ca9e2e 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -324,6 +324,9 @@ private: /// Handles the DIG_FINISHED dig packet: void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta); + + /// Handles the "MC|AdvCdm" plugin message + void HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length); // cSocketThreads::cCallback overrides: virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h index 4bbe3f352..162b74e75 100644 --- a/src/Entities/Floater.h +++ b/src/Entities/Floater.h @@ -7,21 +7,25 @@ +// tolua_begin class cFloater : public cEntity { typedef cFloater super; public: - + + //tolua_end cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime); virtual void SpawnOn(cClientHandle & a_Client) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - + + // tolua_begin bool CanPickup(void) const { return m_CanPickupItem; } int GetOwnerID(void) const { return m_PlayerID; } int GetAttachedMobID(void) const { return m_AttachedMobID; } + // tolua_end protected: // Position @@ -37,4 +41,4 @@ protected: // Entity IDs int m_PlayerID; int m_AttachedMobID; -} ;
\ No newline at end of file +} ; // tolua_export
\ No newline at end of file diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 87c4d2c52..cfa7e9c6f 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -367,10 +367,10 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile) void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { int Seed = m_ChunkGenerator.GetSeed(); - AString Structures = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); - eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld")); - AStringVector Str = StringSplitAndTrim(Structures, ","); + + AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); + AStringVector Str = StringSplitAndTrim(Finishers, ","); for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr) { // Finishers, alpha-sorted: @@ -396,6 +396,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER)); } + else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0) + { + m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed)); + } else if (NoCaseCompare(*itr, "PreSimulator") == 0) { m_FinishGens.push_back(new cFinishGenPreSimulator); diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 4915e6818..02045f76a 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -13,6 +13,7 @@ #include "../Noise.h" #include "../BlockID.h" #include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway() +#include "../Simulator/FireSimulator.h" #include "../World.h" @@ -40,6 +41,125 @@ static inline bool IsWater(BLOCKTYPE a_BlockType) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFinishGenNetherClumpFoliage: + +void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc) +{ + double ChunkX = a_ChunkDesc.GetChunkX() + 0.1; // We can't devide through 0 so lets add 0.1 to all the chunk coordinates. + double ChunkZ = a_ChunkDesc.GetChunkZ() + 0.1; + + NOISE_DATATYPE Val1 = m_Noise.CubicNoise2D((float) (ChunkX * ChunkZ * 0.01f), (float) (ChunkZ / ChunkX * 0.01f)); + NOISE_DATATYPE Val2 = m_Noise.CubicNoise2D((float) (ChunkX / ChunkZ / 0.01f), (float) (ChunkZ * ChunkX / 0.01f)); + + if (Val1 < 0) + { + Val1 = -Val1; + } + + if (Val2 < 0) + { + Val2 = -Val2; + } + + int PosX, PosZ; + // Calculate PosX + if (Val1 <= 1) + { + PosX = (int) floor(Val1 * 16); + } + else + { + PosX = (int) floor(16 / Val1); + } + + // Calculate PosZ + if (Val2 <= 1) + { + PosZ = (int) floor(Val2 * 16); + } + else + { + PosZ = (int) floor(16 / Val2); + } + + for (int y = 1; y < cChunkDef::Height; y++) + { + if (a_ChunkDesc.GetBlockType(PosX, y, PosZ) != E_BLOCK_AIR) + { + continue; + } + if (!g_BlockIsSolid[a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ)]) // Only place on solid blocks + { + continue; + } + + NOISE_DATATYPE BlockType = m_Noise.CubicNoise1D((float) (ChunkX * ChunkZ) / (y * 0.1f)); + if (BlockType < -0.7) + { + TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_BROWN_MUSHROOM); + } + else if (BlockType < 0) + { + TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_RED_MUSHROOM); + } + else if (BlockType < 0.7) + { + TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_FIRE); + } + } +} + + + + + +void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block) +{ + bool IsFireBlock = a_Block == E_BLOCK_FIRE; + + for (int x = a_RelX - 4; x < a_RelX + 4; x++) + { + float xx = (float) a_ChunkDesc.GetChunkX() * cChunkDef::Width + x; + for (int z = a_RelZ - 4; z < a_RelZ + 4; z++) + { + float zz = (float) a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z; + for (int y = a_RelY - 2; y < a_RelY + 2; y++) + { + if (a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) // Don't replace non air blocks. + { + continue; + } + + BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z); + if (!g_BlockIsSolid[BlockBelow]) // Only place on solid blocks + { + continue; + } + + if (IsFireBlock) // don't place fire on non-forever burning blocks. + { + if (!cFireSimulator::DoesBurnForever(BlockBelow)) + { + continue; + } + } + + + NOISE_DATATYPE Val = m_Noise.CubicNoise2D(xx, zz); + if (Val < -0.70) + { + a_ChunkDesc.SetBlockType(x, y, z, a_Block); + } + } + } + } +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cFinishGenSprinkleFoliage: bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ) diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index d89ffed15..2e5732929 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -47,6 +47,28 @@ protected: +class cFinishGenNetherClumpFoliage : + public cFinishGen +{ +public: + cFinishGenNetherClumpFoliage(int a_Seed) : + m_Noise(a_Seed), + m_Seed(a_Seed) + { + } + +protected: + cNoise m_Noise; + int m_Seed; + + void TryPlaceClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block); + virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; +} ; + + + + + class cFinishGenSprinkleFoliage : public cFinishGen { @@ -117,6 +139,7 @@ public: { } + int GetLevel(void) const { return m_Level; } protected: int m_Level; diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index 3d30ab177..a4af706f2 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -205,6 +205,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) { m_State = wcsRecvIdle; m_HTTPServer.RequestFinished(*this, *m_CurrentRequest); + if (!m_CurrentRequest->DoesAllowKeepAlive()) + { + m_State = wcsInvalid; + m_HTTPServer.CloseConnection(*this); + return; + } delete m_CurrentRequest; m_CurrentRequest = NULL; } diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h index 00941f2ae..5b8103554 100644 --- a/src/HTTPServer/HTTPConnection.h +++ b/src/HTTPServer/HTTPConnection.h @@ -41,49 +41,52 @@ public: cHTTPConnection(cHTTPServer & a_HTTPServer); virtual ~cHTTPConnection(); - /// Sends HTTP status code together with a_Reason (used for HTTP errors) + /** Sends HTTP status code together with a_Reason (used for HTTP errors) */ void SendStatusAndReason(int a_StatusCode, const AString & a_Reason); - /// Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm + /** Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm */ void SendNeedAuth(const AString & a_Realm); - /// Sends the headers contained in a_Response + /** Sends the headers contained in a_Response */ void Send(const cHTTPResponse & a_Response); - /// Sends the data as the response (may be called multiple times) + /** Sends the data as the response (may be called multiple times) */ void Send(const void * a_Data, int a_Size); - /// Sends the data as the response (may be called multiple times) + /** Sends the data as the response (may be called multiple times) */ void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); } - /// Indicates that the current response is finished, gets ready for receiving another request (HTTP 1.1 keepalive) + /** Indicates that the current response is finished, gets ready for receiving another request (HTTP 1.1 keepalive) */ void FinishResponse(void); - /// Resets the connection for a new request. Depending on the state, this will send an "InternalServerError" status or a "ResponseEnd" + /** Resets the internal connection state for a new request. + Depending on the state, this will send an "InternalServerError" status or a "ResponseEnd" */ void AwaitNextRequest(void); - /// Terminates the connection; finishes any request being currently processed + /** Terminates the connection; finishes any request being currently processed */ void Terminate(void); protected: typedef std::map<AString, AString> cNameValueMap; - /// The parent webserver that is to be notified of events on this connection + /** The parent webserver that is to be notified of events on this connection */ cHTTPServer & m_HTTPServer; - /// All the incoming data until the entire request header is parsed + /** All the incoming data until the entire request header is parsed */ AString m_IncomingHeaderData; - /// Status in which the request currently is + /** Status in which the request currently is */ eState m_State; - /// Data that is queued for sending, once the socket becomes writable + /** Data that is queued for sending, once the socket becomes writable */ AString m_OutgoingData; - /// The request being currently received (valid only between having parsed the headers and finishing receiving the body) + /** The request being currently received + Valid only between having parsed the headers and finishing receiving the body. */ cHTTPRequest * m_CurrentRequest; - /// Number of bytes that remain to read for the complete body of the message to be received. Valid only in wcsRecvBody + /** Number of bytes that remain to read for the complete body of the message to be received. + Valid only in wcsRecvBody */ int m_CurrentRequestBodyRemaining; diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp index ab23866e6..98627eb8e 100644 --- a/src/HTTPServer/HTTPMessage.cpp +++ b/src/HTTPServer/HTTPMessage.cpp @@ -72,7 +72,8 @@ cHTTPRequest::cHTTPRequest(void) : m_EnvelopeParser(*this), m_IsValid(true), m_UserData(NULL), - m_HasAuth(false) + m_HasAuth(false), + m_AllowKeepAlive(false) { } @@ -236,6 +237,10 @@ void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value) m_HasAuth = true; } } + if ((a_Key == "Connection") && (NoCaseCompare(a_Value, "keep-alive") == 0)) + { + m_AllowKeepAlive = true; + } AddHeader(a_Key, a_Value); } diff --git a/src/HTTPServer/HTTPMessage.h b/src/HTTPServer/HTTPMessage.h index 2a4c2879e..ab3338db7 100644 --- a/src/HTTPServer/HTTPMessage.h +++ b/src/HTTPServer/HTTPMessage.h @@ -35,7 +35,7 @@ public: // Force a virtual destructor in all descendants virtual ~cHTTPMessage() {}; - /// Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length + /** Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length */ void AddHeader(const AString & a_Key, const AString & a_Value); void SetContentType (const AString & a_ContentType) { m_ContentType = a_ContentType; } @@ -51,10 +51,10 @@ protected: cNameValueMap m_Headers; - /// Type of the content; parsed by AddHeader(), set directly by SetContentLength() + /** Type of the content; parsed by AddHeader(), set directly by SetContentLength() */ AString m_ContentType; - /// Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() + /** Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() */ int m_ContentLength; } ; @@ -76,64 +76,71 @@ public: */ int ParseHeaders(const char * a_Data, int a_Size); - /// Returns true if the request did contain a Content-Length header + /** Returns true if the request did contain a Content-Length header */ bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); } - /// Returns the method used in the request + /** Returns the method used in the request */ const AString & GetMethod(void) const { return m_Method; } - /// Returns the URL used in the request + /** Returns the URL used in the request */ const AString & GetURL(void) const { return m_URL; } - /// Returns the URL used in the request, without any parameters + /** Returns the URL used in the request, without any parameters */ AString GetBareURL(void) const; - /// Sets the UserData pointer that is stored within this request. The request doesn't touch this data (doesn't delete it)! + /** Sets the UserData pointer that is stored within this request. + The request doesn't touch this data (doesn't delete it)! */ void SetUserData(void * a_UserData) { m_UserData = a_UserData; } - /// Retrieves the UserData pointer that has been stored within this request. + /** Retrieves the UserData pointer that has been stored within this request. */ void * GetUserData(void) const { return m_UserData; } - /// Returns true if more data is expected for the request headers + /** Returns true if more data is expected for the request headers */ bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); } - /// Returns true if the request did present auth data that was understood by the parser + /** Returns true if the request did present auth data that was understood by the parser */ bool HasAuth(void) const { return m_HasAuth; } - /// Returns the username that the request presented. Only valid if HasAuth() is true + /** Returns the username that the request presented. Only valid if HasAuth() is true */ const AString & GetAuthUsername(void) const { return m_AuthUsername; } - /// Returns the password that the request presented. Only valid if HasAuth() is true + /** Returns the password that the request presented. Only valid if HasAuth() is true */ const AString & GetAuthPassword(void) const { return m_AuthPassword; } + bool DoesAllowKeepAlive(void) const { return m_AllowKeepAlive; } + protected: - /// Parser for the envelope data + /** Parser for the envelope data */ cEnvelopeParser m_EnvelopeParser; - /// True if the data received so far is parsed successfully. When false, all further parsing is skipped + /** True if the data received so far is parsed successfully. When false, all further parsing is skipped */ bool m_IsValid; - /// Bufferred incoming data, while parsing for the request line + /** Bufferred incoming data, while parsing for the request line */ AString m_IncomingHeaderData; - /// Method of the request (GET / PUT / POST / ...) + /** Method of the request (GET / PUT / POST / ...) */ AString m_Method; - /// Full URL of the request + /** Full URL of the request */ AString m_URL; - /// Data that the HTTPServer callbacks are allowed to store. + /** Data that the HTTPServer callbacks are allowed to store. */ void * m_UserData; - /// Set to true if the request contains auth data that was understood by the parser + /** Set to true if the request contains auth data that was understood by the parser */ bool m_HasAuth; - /// The username used for auth + /** The username used for auth */ AString m_AuthUsername; - /// The password used for auth + /** The password used for auth */ AString m_AuthPassword; + /** Set to true if the request indicated that it supports keepalives. + If false, the server will close the connection once the request is finished */ + bool m_AllowKeepAlive; + /** Parses the incoming data for the first line (RequestLine) Returns the number of bytes consumed, or -1 for an error 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 diff --git a/src/Server.cpp b/src/Server.cpp index 49067c17f..5280270b9 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -459,7 +459,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac { return; } - + // Special handling: "stop" and "restart" are built in if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0)) { diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 469680098..e361cbf49 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -4,6 +4,7 @@ #include "RedstoneSimulator.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/NoteEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../Entities/TNTEntity.h" #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" @@ -215,11 +216,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c { case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; - case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; + case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break; + case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: @@ -763,6 +765,29 @@ void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + class cSetPowerToCommandBlock : + public cCommandBlockCallback + { + bool m_IsPowered; + public: + cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} + + virtual bool Item(cCommandBlockEntity * a_CommandBlock) override + { + a_CommandBlock->SetRedstonePower(m_IsPowered); + return false; + } + } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + + m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP); +} + + + + + void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) { switch (a_MyType) diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index 63a5be3d3..bb2efeb8a 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -110,6 +110,8 @@ private: void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); /** Handles doords */ void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); + /** Handles command blocks */ + void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ); /** Handles activator, detector, and powered rails */ void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); /** Handles trapdoors */ @@ -166,6 +168,7 @@ private: switch (Block) { case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_PISTON: case E_BLOCK_STICKY_PISTON: case E_BLOCK_DISPENSER: @@ -220,6 +223,7 @@ private: case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_ACTIVE_COMPARATOR: case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_DISPENSER: case E_BLOCK_DAYLIGHT_SENSOR: diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp index e15058840..5b9a3bb0a 100644 --- a/src/StringCompression.cpp +++ b/src/StringCompression.cpp @@ -11,7 +11,7 @@ /// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2() -int CompressString(const char * a_Data, int a_Length, AString & a_Compressed) +int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor) { uLongf CompressedSize = compressBound(a_Length); @@ -19,7 +19,7 @@ int CompressString(const char * a_Data, int a_Length, AString & a_Compressed) // It saves us one allocation and one memcpy of the entire compressed data // It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010) a_Compressed.resize(CompressedSize); - int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, Z_DEFAULT_COMPRESSION); + int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, a_Factor); if (errorcode != Z_OK) { return errorcode; diff --git a/src/StringCompression.h b/src/StringCompression.h index 459e8f568..3f4e12d2d 100644 --- a/src/StringCompression.h +++ b/src/StringCompression.h @@ -10,7 +10,7 @@ /// Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2() -extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed); +extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor); /// Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress() extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize); diff --git a/src/World.cpp b/src/World.cpp index 134773f67..6520702c7 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -231,6 +231,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_WorldName(a_WorldName), m_IniFileName(m_WorldName + "/world.ini"), m_StorageSchema("Default"), + m_StorageCompressionFactor(6), m_IsSpawnExplicitlySet(false), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), @@ -512,6 +513,7 @@ void cWorld::Start(void) } m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema); + m_StorageCompressionFactor = IniFile.GetValueSetI ("Storage", "CompressionFactor", m_StorageCompressionFactor); m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3); m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3); m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false); @@ -585,7 +587,7 @@ void cWorld::Start(void) m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1); m_Lighting.Start(this); - m_Storage.Start(this, m_StorageSchema); + m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor ); m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile); m_ChunkSender.Start(this); m_TickThread.Start(); @@ -1142,6 +1144,15 @@ bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl +bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback) +{ + return m_ChunkMap->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { return m_ChunkMap->GetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4); @@ -2760,9 +2771,6 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp { Monster->SetPosition(a_PosX, a_PosY, a_PosZ); } - - // Because it's logical that ALL mob spawns need spawn effects, not just spawners - BroadcastSoundParticleEffect(2004, (int)a_PosX, (int)a_PosY, (int)a_PosZ, 0); return SpawnMobFinalize(Monster); } diff --git a/src/World.h b/src/World.h index 1ecf41507..1a7ad0cb1 100644 --- a/src/World.h +++ b/src/World.h @@ -46,12 +46,13 @@ class cMobCensus; typedef std::list< cPlayer * > cPlayerList; -typedef cItemCallback<cPlayer> cPlayerListCallback; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cPlayer> cPlayerListCallback; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; @@ -466,6 +467,9 @@ public: /// 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 + 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 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 @@ -681,6 +685,8 @@ private: /// 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 eDimension m_Dimension; diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e1205f2be..447296c7f 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -10,6 +10,7 @@ #include "FastNBT.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -219,8 +220,23 @@ void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox) void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note) { m_Writer.BeginCompound(""); - AddBasicTileEntity(a_Note, "Music"); - m_Writer.AddByte("note", a_Note->GetPitch()); + AddBasicTileEntity(a_Note, "Music"); + m_Writer.AddByte("note", a_Note->GetPitch()); + m_Writer.EndCompound(); +} + + + + + +void cNBTChunkSerializer::AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock) +{ + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_CmdBlock, "Control"); + m_Writer.AddString("Command", a_CmdBlock->GetCommand()); + m_Writer.AddInt ("SuccessCount", a_CmdBlock->GetResult()); + m_Writer.AddString("LastOutput", a_CmdBlock->GetLastOutput()); + m_Writer.AddByte ("TrackOutput", 1); // TODO 2014-01-18 xdot: Figure out what TrackOutput is and save it. m_Writer.EndCompound(); } @@ -639,15 +655,16 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity) // Add tile-entity into NBT: switch (a_Entity->GetBlockType()) { - case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; - case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; - case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; - case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; - case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; + case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; + case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; + case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; + case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; + case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; case E_BLOCK_SIGN_POST: - case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; - case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; - case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; + case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; + case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; + case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; + case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) a_Entity); break; default: { ASSERT(!"Unhandled block entity saved into Anvil"); diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 9d4ac208c..245b68063 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -21,6 +21,7 @@ class cEntity; class cBlockEntity; class cBoat; class cChestEntity; +class cCommandBlockEntity; class cDispenserEntity; class cDropperEntity; class cFurnaceEntity; @@ -92,6 +93,7 @@ protected: void AddJukeboxEntity (cJukeboxEntity * a_Jukebox); void AddNoteEntity (cNoteEntity * a_Note); void AddSignEntity (cSignEntity * a_Sign); + void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock); // Entities: void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 72c47aa14..96a77152b 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -15,6 +15,7 @@ #include "../StringCompression.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -58,8 +59,9 @@ Since only the header is actually in the memory, this number can be high, but st /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cWSSAnvil: -cWSSAnvil::cWSSAnvil(cWorld * a_World) : - super(a_World) +cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) : + super(a_World), + m_CompressionFactor(a_CompressionFactor) { // Create a level.dat file for mapping tools, if it doesn't already exist: AString fnam; @@ -272,7 +274,7 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data) } Writer.Finish(); - CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data); + CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data, m_CompressionFactor); return true; } @@ -566,6 +568,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { LoadChestFromNBT(a_BlockEntities, a_NBT, Child); } + else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0) + { + LoadCommandBlockFromNBT(a_BlockEntities, a_NBT, Child); + } else if (strncmp(a_NBT.GetData(sID), "Dropper", a_NBT.GetDataLength(sID)) == 0) { LoadDropperFromNBT(a_BlockEntities, a_NBT, Child); @@ -914,6 +920,43 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse +void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); + int x, y, z; + if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + { + return; + } + std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(x, y, z, m_World)); + + int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command"); + if (currentLine >= 0) + { + CmdBlock->SetCommand(a_NBT.GetString(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "SuccessCount"); + if (currentLine >= 0) + { + CmdBlock->SetResult(a_NBT.GetInt(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput"); + if (currentLine >= 0) + { + CmdBlock->SetLastOutput(a_NBT.GetString(currentLine)); + } + + // TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it. + + a_BlockEntities.push_back(CmdBlock.release()); +} + + + + + void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength) { if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0) diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 0a7406267..5093ad083 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -47,7 +47,7 @@ class cWSSAnvil : public: - cWSSAnvil(cWorld * a_World); + cWSSAnvil(cWorld * a_World, int a_CompressionFactor); virtual ~cWSSAnvil(); protected: @@ -89,6 +89,8 @@ protected: cCriticalSection m_CS; cMCAFiles m_Files; // a MRU cache of MCA files + + int m_CompressionFactor; /// Gets chunk data from the correct file; locks file CS as needed bool GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data); @@ -129,14 +131,15 @@ protected: */ void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0); - void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); - void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); + void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength); diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index e2556b96e..ea17a8ec1 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -193,7 +193,7 @@ cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk) // Load it anew: AString FileName; Printf(FileName, "%s/X%i_Z%i.pak", m_World->GetName().c_str(), LayerX, LayerZ ); - cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ); + cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ, m_CompressionFactor); if (f == NULL) { return NULL; @@ -399,8 +399,9 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En return; \ } -cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ) : +cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor) : m_FileName(a_FileName), + m_CompressionFactor(a_CompressionFactor), m_LayerX(a_LayerX), m_LayerZ(a_LayerZ), m_NumDirty(0), @@ -648,7 +649,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() // Re-compress data AString CompressedData; { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData); + int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor); if (errorcode != Z_OK) { LOGERROR("Error %d compressing data for chunk [%d, %d]", @@ -786,7 +787,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() // Re-compress data AString CompressedData; { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData); + int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor); if (errorcode != Z_OK) { LOGERROR("Error %d compressing data for chunk [%d, %d]", @@ -939,7 +940,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld // Compress the data: AString CompressedData; - int errorcode = CompressString(Data.data(), Data.size(), CompressedData); + int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor); if ( errorcode != Z_OK ) { LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h index 3223a986e..64b8d7f31 100644 --- a/src/WorldStorage/WSSCompact.h +++ b/src/WorldStorage/WSSCompact.h @@ -53,7 +53,7 @@ class cWSSCompact : public cWSSchema { public: - cWSSCompact(cWorld * a_World) : cWSSchema(a_World) {} + cWSSCompact(cWorld * a_World, int a_CompressionFactor) : cWSSchema(a_World), m_CompressionFactor(a_CompressionFactor) {} virtual ~cWSSCompact(); protected: @@ -74,7 +74,7 @@ protected: { public: - cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ); + cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor); ~cPAKFile(); bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data); @@ -95,6 +95,7 @@ protected: protected: AString m_FileName; + int m_CompressionFactor; int m_LayerX; int m_LayerZ; @@ -119,6 +120,8 @@ protected: cCriticalSection m_CS; cPAKFiles m_PAKFiles; // A MRU cache of PAK files + int m_CompressionFactor; + /// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache cPAKFile * LoadPAKFile(const cChunkCoords & a_Chunk); diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index 6aec525a8..711c8612f 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -68,11 +68,11 @@ cWorldStorage::~cWorldStorage() -bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName) +bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor ) { m_World = a_World; m_StorageSchemaName = a_StorageSchemaName; - InitSchemas(); + InitSchemas(a_StorageCompressionFactor); return super::Start(); } @@ -197,11 +197,11 @@ void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk) -void cWorldStorage::InitSchemas(void) +void cWorldStorage::InitSchemas(int a_StorageCompressionFactor) { // The first schema added is considered the default - m_Schemas.push_back(new cWSSAnvil (m_World)); - m_Schemas.push_back(new cWSSCompact (m_World)); + m_Schemas.push_back(new cWSSAnvil (m_World,a_StorageCompressionFactor)); + m_Schemas.push_back(new cWSSCompact (m_World,a_StorageCompressionFactor)); m_Schemas.push_back(new cWSSForgetful(m_World)); // Add new schemas here diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h index 06cae1717..bb189b6c9 100644 --- a/src/WorldStorage/WorldStorage.h +++ b/src/WorldStorage/WorldStorage.h @@ -76,7 +76,7 @@ public: void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); void UnqueueSave(const cChunkCoords & a_Chunk); - bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args + bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event void WaitForFinish(void); void WaitForLoadQueueEmpty(void); @@ -126,7 +126,7 @@ protected: /// The one storage schema used for saving cWSSchema * m_SaveSchema; - void InitSchemas(void); + void InitSchemas(int a_StorageCompressionFactor); virtual void Execute(void) override; |