summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTiger Wang <ziwei.tiger@hotmail.co.uk>2014-01-19 14:55:22 +0100
committerTiger Wang <ziwei.tiger@hotmail.co.uk>2014-01-19 14:55:22 +0100
commit82b2290b74519ab86d6abae463cbe0c1d8ac5868 (patch)
tree98855d56f18990731d88c283c6990d98b3d26245 /src
parentMinecart collision and general improvements (diff)
parentUpdated core (diff)
downloadcuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar
cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.gz
cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.bz2
cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.lz
cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.xz
cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.zst
cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.zip
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/Bindings/ManualBindings.cpp22
-rw-r--r--src/BlockEntities/BlockEntity.cpp24
-rw-r--r--src/BlockEntities/CommandBlockEntity.cpp197
-rw-r--r--src/BlockEntities/CommandBlockEntity.h91
-rw-r--r--src/BlockEntities/FurnaceEntity.cpp4
-rw-r--r--src/BlockEntities/HopperEntity.cpp4
-rw-r--r--src/Blocks/BlockChest.h10
-rw-r--r--src/Blocks/BlockComparator.h2
-rw-r--r--src/Blocks/BlockDoor.h2
-rw-r--r--src/Blocks/BlockDropSpenser.h2
-rw-r--r--src/Blocks/BlockEnderchest.h2
-rw-r--r--src/Blocks/BlockFenceGate.h4
-rw-r--r--src/Blocks/BlockFurnace.h2
-rw-r--r--src/Blocks/BlockPiston.cpp2
-rw-r--r--src/Blocks/BlockPumpkin.h2
-rw-r--r--src/Blocks/BlockRedstoneRepeater.h2
-rw-r--r--src/Blocks/BlockStairs.h2
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Chunk.cpp34
-rw-r--r--src/Chunk.h16
-rw-r--r--src/ChunkMap.cpp17
-rw-r--r--src/ChunkMap.h23
-rw-r--r--src/ClientHandle.cpp86
-rw-r--r--src/ClientHandle.h3
-rw-r--r--src/Defines.h1
-rw-r--r--src/Entities/Entity.cpp6
-rw-r--r--src/Entities/Entity.h8
-rw-r--r--src/Entities/Floater.h10
-rw-r--r--src/Entities/Minecart.cpp35
-rw-r--r--src/Entities/Minecart.h12
-rw-r--r--src/Entities/Player.cpp17
-rw-r--r--src/Entities/ProjectileEntity.cpp12
-rw-r--r--src/Generating/ComposableGenerator.cpp10
-rw-r--r--src/Generating/FinishGen.cpp120
-rw-r--r--src/Generating/FinishGen.h23
-rw-r--r--src/HTTPServer/HTTPConnection.cpp6
-rw-r--r--src/HTTPServer/HTTPConnection.h31
-rw-r--r--src/HTTPServer/HTTPMessage.cpp7
-rw-r--r--src/HTTPServer/HTTPMessage.h51
-rw-r--r--src/Inventory.cpp2
-rw-r--r--src/Item.cpp32
-rw-r--r--src/Item.h41
-rw-r--r--src/ItemGrid.cpp8
-rw-r--r--src/Items/ItemBed.h2
-rw-r--r--src/Items/ItemComparator.h2
-rw-r--r--src/Items/ItemMinecart.h2
-rw-r--r--src/Items/ItemRedstoneRepeater.h2
-rw-r--r--src/Items/ItemSign.h2
-rw-r--r--src/Mobs/Monster.cpp2
-rw-r--r--src/Protocol/Protocol125.cpp18
-rw-r--r--src/Protocol/Protocol132.cpp8
-rw-r--r--src/Protocol/Protocol14x.cpp2
-rw-r--r--src/Protocol/Protocol17x.cpp104
-rw-r--r--src/Server.cpp2
-rw-r--r--src/Simulator/RedstoneSimulator.cpp27
-rw-r--r--src/Simulator/RedstoneSimulator.h4
-rw-r--r--src/StringCompression.cpp4
-rw-r--r--src/StringCompression.h2
-rw-r--r--src/UI/SlotArea.cpp19
-rw-r--r--src/UI/Window.cpp2
-rw-r--r--src/World.cpp40
-rw-r--r--src/World.h21
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp39
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--src/WorldStorage/WSSAnvil.cpp53
-rw-r--r--src/WorldStorage/WSSAnvil.h21
-rw-r--r--src/WorldStorage/WSSCompact.cpp11
-rw-r--r--src/WorldStorage/WSSCompact.h7
-rw-r--r--src/WorldStorage/WorldStorage.cpp10
-rw-r--r--src/WorldStorage/WorldStorage.h4
-rw-r--r--src/main.cpp13
72 files changed, 1139 insertions, 276 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/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp
index f15553968..c6643bcff 100644
--- a/src/BlockEntities/FurnaceEntity.cpp
+++ b/src/BlockEntities/FurnaceEntity.cpp
@@ -307,7 +307,7 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
/// Updates the current recipe, based on the current input
void cFurnaceEntity::UpdateInput(void)
{
- if (!m_Contents.GetSlot(fsInput).IsStackableWith(m_LastInput))
+ if (!m_Contents.GetSlot(fsInput).IsEqual(m_LastInput))
{
// The input is different from what we had before, reset the cooking time
m_TimeCooked = 0;
@@ -417,7 +417,7 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const
return true;
}
- if (!m_Contents.GetSlot(fsOutput).IsStackableWith(*m_CurrentRecipe->Out))
+ if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out))
{
// The output slot is blocked with something that cannot be stacked with the recipe's output
return false;
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index eac59e74d..2255cad64 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -407,7 +407,7 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl
m_Contents.SetSlot(i, One);
return true;
}
- else if (m_Contents.GetSlot(i).IsStackableWith(One))
+ else if (m_Contents.GetSlot(i).IsEqual(One))
{
if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
{
@@ -544,7 +544,7 @@ bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstS
}
for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
{
- if (m_Contents.GetSlot(i).IsStackableWith(DestSlot))
+ if (m_Contents.GetSlot(i).IsEqual(DestSlot))
{
if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
{
diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h
index 488c58ac5..88f7c4b32 100644
--- a/src/Blocks/BlockChest.h
+++ b/src/Blocks/BlockChest.h
@@ -42,13 +42,13 @@ public:
{
return false;
}
- double rot = a_Player->GetRotation();
+ double yaw = a_Player->GetYaw();
if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
- a_BlockMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3;
+ a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
return true;
}
if (
@@ -56,12 +56,12 @@ public:
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
- a_BlockMeta = (rot < 0) ? 4 : 5;
+ a_BlockMeta = (yaw < 0) ? 4 : 5;
return true;
}
// Single chest, get meta from rotation only
- a_BlockMeta = RotationToMetaData(rot);
+ a_BlockMeta = RotationToMetaData(yaw);
return true;
}
@@ -80,7 +80,7 @@ public:
return;
}
- double rot = a_Player->GetRotation();
+ double rot = a_Player->GetYaw(); // FIXME: Rename rot to yaw
// Choose meta from player rotation, choose only between 2 or 3
NIBBLETYPE NewMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3;
if (
diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h
index e7e18bac9..5a8e54eda 100644
--- a/src/Blocks/BlockComparator.h
+++ b/src/Blocks/BlockComparator.h
@@ -53,7 +53,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h
index 03a79d47d..1e86446dd 100644
--- a/src/Blocks/BlockDoor.h
+++ b/src/Blocks/BlockDoor.h
@@ -42,7 +42,7 @@ public:
}
a_BlockType = m_BlockType;
- a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
+ a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h
index b7f20825d..ce9cc0c5d 100644
--- a/src/Blocks/BlockDropSpenser.h
+++ b/src/Blocks/BlockDropSpenser.h
@@ -31,7 +31,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for dispenser placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch());
+ a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
} ;
diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h
index 50d8e38e0..b648248d0 100644
--- a/src/Blocks/BlockEnderchest.h
+++ b/src/Blocks/BlockEnderchest.h
@@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index 6423a7cb0..779f12ee1 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -25,7 +25,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
+ a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}
@@ -33,7 +33,7 @@ public:
virtual void OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetRotation());
+ NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetYaw());
OldMetaData ^= 4; // Toggle the gate
if ((OldMetaData & 1) == (NewMetaData & 1))
{
diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h
index 5b067d7b7..693eac331 100644
--- a/src/Blocks/BlockFurnace.h
+++ b/src/Blocks/BlockFurnace.h
@@ -35,7 +35,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for furnace placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0);
+ a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), 0);
return true;
}
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 3e1ca1d15..88259d96e 100644
--- a/src/Blocks/BlockPiston.cpp
+++ b/src/Blocks/BlockPiston.cpp
@@ -60,7 +60,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
)
{
a_BlockType = m_BlockType;
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch());
+ a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h
index 724241935..5187f24eb 100644
--- a/src/Blocks/BlockPumpkin.h
+++ b/src/Blocks/BlockPumpkin.h
@@ -86,7 +86,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
+ a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h
index 1fcddd4f8..713664659 100644
--- a/src/Blocks/BlockRedstoneRepeater.h
+++ b/src/Blocks/BlockRedstoneRepeater.h
@@ -25,7 +25,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h
index fa378e4b5..e463612f5 100644
--- a/src/Blocks/BlockStairs.h
+++ b/src/Blocks/BlockStairs.h
@@ -26,7 +26,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
switch (a_BlockFace)
{
case BLOCK_FACE_TOP: break;
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 9348a1825..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",
@@ -629,6 +700,17 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
return;
}
+ case DIG_STATUS_DROP_STACK:
+ {
+ if (PlgMgr->CallHookPlayerTossingItem(*m_Player))
+ {
+ // A plugin doesn't agree with the tossing. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
+ return;
+ }
+ m_Player->TossItem(false, 64); // Toss entire slot - if there aren't enough items, the maximum will be ejected
+ return;
+ }
+
default:
{
ASSERT(!"Unhandled DIG_STATUS");
@@ -1026,7 +1108,7 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO
return;
}
- m_Player->SetRotation (a_Rotation);
+ m_Player->SetYaw (a_Rotation);
m_Player->SetHeadYaw (a_Rotation);
m_Player->SetPitch (a_Pitch);
m_Player->SetTouchGround(a_IsOnGround);
@@ -1058,7 +1140,7 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_
m_Player->SetStance (a_Stance);
m_Player->SetTouchGround(a_IsOnGround);
m_Player->SetHeadYaw (a_Rotation);
- m_Player->SetRotation (a_Rotation);
+ m_Player->SetYaw (a_Rotation);
m_Player->SetPitch (a_Pitch);
}
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/Defines.h b/src/Defines.h
index cc04d8026..7a86f499e 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -85,6 +85,7 @@ enum
DIG_STATUS_STARTED = 0,
DIG_STATUS_CANCELLED = 1,
DIG_STATUS_FINISHED = 2,
+ DIG_STATUS_DROP_STACK= 3,
DIG_STATUS_DROP_HELD = 4,
DIG_STATUS_SHOOT_EAT = 5,
} ;
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 8e0d0b9a7..565c78dfd 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -263,16 +263,16 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
-void cEntity::SetRotationFromSpeed(void)
+void cEntity::SetYawFromSpeed(void)
{
const double EPS = 0.0000001;
if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS))
{
// atan2() may overflow or is undefined, pick any number
- SetRotation(0);
+ SetYaw(0);
return;
}
- SetRotation(atan2(m_Speed.x, m_Speed.z) * 180 / PI);
+ SetYaw(atan2(m_Speed.x, m_Speed.z) * 180 / PI);
}
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 878e69668..91463bfd6 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -154,8 +154,7 @@ public:
double GetPosX (void) const { return m_Pos.x; }
double GetPosY (void) const { return m_Pos.y; }
double GetPosZ (void) const { return m_Pos.z; }
- const Vector3d & GetRot (void) const { return m_Rot; }
- double GetRotation (void) const { return m_Rot.x; } // OBSOLETE, use GetYaw() instead
+ const Vector3d & GetRot (void) const { return m_Rot; } // OBSOLETE, use individual GetYaw(), GetPitch, GetRoll() components
double GetYaw (void) const { return m_Rot.x; }
double GetPitch (void) const { return m_Rot.y; }
double GetRoll (void) const { return m_Rot.z; }
@@ -177,8 +176,7 @@ public:
void SetPosZ (double a_PosZ);
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
- void SetRot (const Vector3f & a_Rot);
- void SetRotation(double a_Rotation) { SetYaw(a_Rotation); } // OBSOLETE, use SetYaw() instead
+ void SetRot (const Vector3f & a_Rot); // OBSOLETE, use individual SetYaw(), SetPitch(), SetRoll() components
void SetYaw (double a_Yaw);
void SetPitch (double a_Pitch);
void SetRoll (double a_Roll);
@@ -223,7 +221,7 @@ public:
void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; }
/// Sets the rotation to match the speed vector (entity goes "face-forward")
- void SetRotationFromSpeed(void);
+ void SetYawFromSpeed(void);
/// Sets the pitch to match the speed vector (entity gies "face-forward")
void SetPitchFromSpeed(void);
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/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index ad63f848e..c8f43a3e6 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -118,6 +118,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
}
}
a_ClientHandle.SendSpawnVehicle(*this, 10, SubType); // 10 = Minecarts, SubType = What type of Minecart
+ a_ClientHandle.SendEntityMetadata(*this);
}
@@ -212,7 +213,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
- SetRotation(270);
+ SetYaw(270);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0); // Don't move vertically as on ground
SetSpeedX(0); // Correct diagonal movement from curved rails
@@ -238,7 +239,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_XM_XP: // EASTWEST
{
- SetRotation(180);
+ SetYaw(180);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedZ(0);
@@ -261,7 +262,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
- SetRotation(270);
+ SetYaw(270);
SetSpeedX(0);
if (GetSpeedZ() >= 0)
@@ -283,7 +284,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
- SetRotation(270);
+ SetYaw(270);
SetSpeedX(0);
if (GetSpeedZ() > 0)
@@ -305,7 +306,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
- SetRotation(180);
+ SetYaw(180);
SetSpeedZ(0);
if (GetSpeedX() >= 0)
@@ -325,7 +326,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
- SetRotation(180);
+ SetYaw(180);
SetSpeedZ(0);
if (GetSpeedX() > 0)
@@ -345,7 +346,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
{
- SetRotation(315); // Set correct rotation server side
+ SetYaw(315); // Set correct rotation server side
SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart
TestBlockCollision(a_RailMeta);
@@ -357,7 +358,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
{
- SetRotation(225);
+ SetYaw(225);
SetPosY(floor(GetPosY()) + 0.55);
TestBlockCollision(a_RailMeta);
@@ -367,7 +368,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
{
- SetRotation(135);
+ SetYaw(135);
SetPosY(floor(GetPosY()) + 0.55);
TestBlockCollision(a_RailMeta);
@@ -377,7 +378,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
{
- SetRotation(45);
+ SetYaw(45);
SetPosY(floor(GetPosY()) + 0.55);
TestBlockCollision(a_RailMeta);
@@ -413,7 +414,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
- SetRotation(270);
+ SetYaw(270);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedX(0);
@@ -435,7 +436,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
}
case E_META_RAIL_XM_XP: // EASTWEST
{
- SetRotation(180);
+ SetYaw(180);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedZ(0);
@@ -841,10 +842,12 @@ void cMinecart::Destroyed()
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cEmptyMinecart:
+// cRideableMinecart:
-cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) :
- super(mpNone, a_X, a_Y, a_Z)
+cRideableMinecart::cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height) :
+ super(mpNone, a_X, a_Y, a_Z),
+ m_Content(a_Content),
+ m_Height(a_Height)
{
}
@@ -852,7 +855,7 @@ cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) :
-void cEmptyMinecart::OnRightClicked(cPlayer & a_Player)
+void cRideableMinecart::OnRightClicked(cPlayer & a_Player)
{
if (m_Attachee != NULL)
{
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 1c3ea3220..a4ecb33ad 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -93,18 +93,24 @@ protected:
-class cEmptyMinecart :
+class cRideableMinecart :
public cMinecart
{
typedef cMinecart super;
public:
- CLASS_PROTODEF(cEmptyMinecart);
+ CLASS_PROTODEF(cRideableMinecart);
- cEmptyMinecart(double a_X, double a_Y, double a_Z);
+ cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height);
+ const cItem & GetContent(void) const {return m_Content;}
+ int GetBlockHeight(void) const {return m_Height;}
// cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override;
+protected:
+
+ cItem m_Content;
+ int m_Height;
} ;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index fa6422389..c1f2456eb 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1382,16 +1382,21 @@ void cPlayer::TossItem(
cItem DroppedItem(GetInventory().GetEquippedItem());
if (!DroppedItem.IsEmpty())
{
- if (GetInventory().RemoveOneEquippedItem())
+ char NewAmount = a_Amount;
+ if (NewAmount > GetInventory().GetEquippedItem().m_ItemCount)
{
- DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again
- Drops.push_back(DroppedItem);
+ NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there
}
+
+ GetInventory().GetHotbarGrid().ChangeSlotCount(GetInventory().GetEquippedSlotNum() /* Returns hotbar subslot, which HotbarGrid takes */, -a_Amount);
+
+ DroppedItem.m_ItemCount = NewAmount;
+ Drops.push_back(DroppedItem);
}
}
}
double vX = 0, vY = 0, vZ = 0;
- EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY);
+ EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
}
@@ -1523,7 +1528,7 @@ bool cPlayer::LoadFromDisk()
Json::Value & JSON_PlayerRotation = root["rotation"];
if (JSON_PlayerRotation.size() == 3)
{
- SetRotation ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
+ SetYaw ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble());
SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble());
}
@@ -1586,7 +1591,7 @@ bool cPlayer::SaveToDisk()
JSON_PlayerPosition.append(Json::Value(GetPosZ()));
Json::Value JSON_PlayerRotation;
- JSON_PlayerRotation.append(Json::Value(GetRotation()));
+ JSON_PlayerRotation.append(Json::Value(GetYaw()));
JSON_PlayerRotation.append(Json::Value(GetPitch()));
JSON_PlayerRotation.append(Json::Value(GetRoll()));
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 9e5069ba6..12ce9a303 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -206,7 +206,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
m_IsInGround(false)
{
SetSpeed(a_Speed);
- SetRotationFromSpeed();
+ SetYawFromSpeed();
SetPitchFromSpeed();
}
@@ -350,7 +350,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NewSpeed.y += m_Gravity / 20;
NewSpeed *= TracerCallback.GetSlowdownCoeff();
SetSpeed(NewSpeed);
- SetRotationFromSpeed();
+ SetYawFromSpeed();
SetPitchFromSpeed();
// DEBUG:
@@ -358,7 +358,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ(),
- GetRotation(), GetPitch()
+ GetYaw(), GetPitch()
);
}
@@ -369,7 +369,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
{
// Default spawning - use the projectile kind to spawn an object:
- a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch()));
+ a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetYaw()), ANGLE_TO_PROTO(GetPitch()));
a_Client.SendEntityMetadata(*this);
}
@@ -402,11 +402,11 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
{
SetSpeed(a_Speed);
SetMass(0.1);
- SetRotationFromSpeed();
+ SetYawFromSpeed();
SetPitchFromSpeed();
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
- GetRotation(), GetPitch()
+ GetYaw(), GetPitch()
);
}
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/Inventory.cpp b/src/Inventory.cpp
index a7f77cf6d..0e1cedc85 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -83,7 +83,7 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int
{
NumLeft -= MaxStack;
}
- else if (Slot.IsStackableWith(a_ItemStack))
+ else if (Slot.IsEqual(a_ItemStack))
{
NumLeft -= MaxStack - Slot.m_ItemCount;
}
diff --git a/src/Item.cpp b/src/Item.cpp
index a44515019..9170006b6 100644
--- a/src/Item.cpp
+++ b/src/Item.cpp
@@ -91,28 +91,6 @@ bool cItem::DamageItem(short a_Amount)
-bool cItem::IsStackableWith(const cItem & a_OtherStack) const
-{
- if (a_OtherStack.m_ItemType != m_ItemType)
- {
- return false;
- }
- if (a_OtherStack.m_ItemDamage != m_ItemDamage)
- {
- return false;
- }
- if (a_OtherStack.m_Enchantments != m_Enchantments)
- {
- return false;
- }
-
- return true;
-}
-
-
-
-
-
bool cItem::IsFullStack(void) const
{
return (m_ItemCount >= ItemHandler(m_ItemType)->GetMaxStackSize());
@@ -153,6 +131,14 @@ void cItem::GetJson(Json::Value & a_OutValue) const
{
a_OutValue["ench"] = Enchantments;
}
+ if (!IsCustomNameEmpty())
+ {
+ a_OutValue["Name"] = m_CustomName;
+ }
+ if (!IsLoreEmpty())
+ {
+ a_OutValue["Lore"] = m_Lore;
+ }
}
}
@@ -169,6 +155,8 @@ void cItem::FromJson(const Json::Value & a_Value)
m_ItemDamage = (short)a_Value.get("Health", -1 ).asInt();
m_Enchantments.Clear();
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
+ m_CustomName = a_Value.get("Name", "").asString();
+ m_Lore = a_Value.get("Lore", "").asString();
}
}
diff --git a/src/Item.h b/src/Item.h
index 64a30ade1..727965112 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -36,7 +36,9 @@ public:
cItem(void) :
m_ItemType(E_ITEM_EMPTY),
m_ItemCount(0),
- m_ItemDamage(0)
+ m_ItemDamage(0),
+ m_CustomName(""),
+ m_Lore("")
{
}
@@ -46,12 +48,16 @@ public:
short a_ItemType,
char a_ItemCount = 1,
short a_ItemDamage = 0,
- const AString & a_Enchantments = ""
+ const AString & a_Enchantments = "",
+ const AString & a_CustomName = "",
+ const AString & a_Lore = ""
) :
m_ItemType (a_ItemType),
m_ItemCount (a_ItemCount),
m_ItemDamage (a_ItemDamage),
- m_Enchantments(a_Enchantments)
+ m_Enchantments(a_Enchantments),
+ m_CustomName (a_CustomName),
+ m_Lore (a_Lore)
{
if (!IsValidItem(m_ItemType))
{
@@ -69,7 +75,9 @@ public:
m_ItemType (a_CopyFrom.m_ItemType),
m_ItemCount (a_CopyFrom.m_ItemCount),
m_ItemDamage (a_CopyFrom.m_ItemDamage),
- m_Enchantments(a_CopyFrom.m_Enchantments)
+ m_Enchantments(a_CopyFrom.m_Enchantments),
+ m_CustomName (a_CopyFrom.m_CustomName),
+ m_Lore (a_CopyFrom.m_Lore)
{
}
@@ -80,6 +88,8 @@ public:
m_ItemCount = 0;
m_ItemDamage = 0;
m_Enchantments.Clear();
+ m_CustomName = "";
+ m_Lore = "";
}
@@ -96,13 +106,16 @@ public:
return ((m_ItemType <= 0) || (m_ItemCount <= 0));
}
-
+ /* Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored!
+ */
bool IsEqual(const cItem & a_Item) const
{
return (
IsSameType(a_Item) &&
(m_ItemDamage == a_Item.m_ItemDamage) &&
- (m_Enchantments == a_Item.m_Enchantments)
+ (m_Enchantments == a_Item.m_Enchantments) &&
+ (m_CustomName == a_Item.m_CustomName) &&
+ (m_Lore == a_Item.m_Lore)
);
}
@@ -111,7 +124,16 @@ public:
{
return (m_ItemType == a_Item.m_ItemType) || (IsEmpty() && a_Item.IsEmpty());
}
-
+
+
+ bool IsBothNameAndLoreEmpty(void) const
+ {
+ return (m_CustomName.empty() && m_Lore.empty());
+ }
+
+
+ bool IsCustomNameEmpty(void) const { return (m_CustomName.empty()); }
+ bool IsLoreEmpty(void) const { return (m_Lore.empty()); }
/// Returns a copy of this item with m_ItemCount set to 1. Useful to preserve enchantments etc. on stacked items
cItem CopyOne(void) const;
@@ -127,9 +149,6 @@ public:
inline bool IsDamageable(void) const { return (GetMaxDamage() > 0); }
- /// Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored!
- bool IsStackableWith(const cItem & a_OtherStack) const;
-
/// Returns true if the item is stacked up to its maximum stacking.
bool IsFullStack(void) const;
@@ -155,6 +174,8 @@ public:
short m_ItemType;
char m_ItemCount;
short m_ItemDamage;
+ AString m_CustomName;
+ AString m_Lore;
cEnchantments m_Enchantments;
};
// tolua_end
diff --git a/src/ItemGrid.cpp b/src/ItemGrid.cpp
index d2e6b1c69..e8b58695f 100644
--- a/src/ItemGrid.cpp
+++ b/src/ItemGrid.cpp
@@ -226,7 +226,7 @@ int cItemGrid::HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks)
NumLeft -= MaxStack;
}
}
- else if (m_Slots[i].IsStackableWith(a_ItemStack))
+ else if (m_Slots[i].IsEqual(a_ItemStack))
{
NumLeft -= MaxStack - m_Slots[i].m_ItemCount;
}
@@ -275,7 +275,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit
(a_PrioritarySlot != -1) &&
(
m_Slots[a_PrioritarySlot].IsEmpty() ||
- m_Slots[a_PrioritarySlot].IsStackableWith(a_ItemStack)
+ m_Slots[a_PrioritarySlot].IsEqual(a_ItemStack)
)
)
{
@@ -285,7 +285,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit
// Scan existing stacks:
for (int i = m_NumSlots - 1; i >= 0; i--)
{
- if (m_Slots[i].IsStackableWith(a_ItemStack))
+ if (m_Slots[i].IsEqual(a_ItemStack))
{
NumLeft -= AddItemToSlot(a_ItemStack, i, NumLeft, MaxStack);
}
@@ -438,7 +438,7 @@ int cItemGrid::HowManyItems(const cItem & a_Item)
int res = 0;
for (int i = 0; i < m_NumSlots; i++)
{
- if (m_Slots[i].IsStackableWith(a_Item))
+ if (m_Slots[i].IsEqual(a_Item))
{
res += m_Slots[i].m_ItemCount;
}
diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h
index ab4182eea..9b7c8bff8 100644
--- a/src/Items/ItemBed.h
+++ b/src/Items/ItemBed.h
@@ -37,7 +37,7 @@ public:
return false;
}
- a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetYaw());
// Check if there is empty space for the foot section:
Vector3i Direction = cBlockBedHandler::MetaDataToDirection(a_BlockMeta);
diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h
index 3fbb7603d..3a5d1d200 100644
--- a/src/Items/ItemComparator.h
+++ b/src/Items/ItemComparator.h
@@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = E_BLOCK_INACTIVE_COMPARATOR;
- a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
} ;
diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h
index f8eb31a49..4071f8c60 100644
--- a/src/Items/ItemMinecart.h
+++ b/src/Items/ItemMinecart.h
@@ -60,7 +60,7 @@ public:
cMinecart * Minecart = NULL;
switch (m_ItemType)
{
- case E_ITEM_MINECART: Minecart = new cEmptyMinecart (x, y, z); break;
+ case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break;
case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break;
case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break;
case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break;
diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h
index f69f24eb8..e71c8e672 100644
--- a/src/Items/ItemRedstoneRepeater.h
+++ b/src/Items/ItemRedstoneRepeater.h
@@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF;
- a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
} ;
diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h
index 5ccd79e29..8c134ab83 100644
--- a/src/Items/ItemSign.h
+++ b/src/Items/ItemSign.h
@@ -34,7 +34,7 @@ public:
{
if (a_BlockFace == BLOCK_FACE_TOP)
{
- a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetYaw());
a_BlockType = E_BLOCK_SIGN_POST;
}
else
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 76df76633..98b6c1d28 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -208,7 +208,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
Distance.Normalize();
VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch );
SetHeadYaw (Rotation);
- SetRotation( Rotation );
+ SetYaw( Rotation );
SetPitch( -Pitch );
}
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 48c085ae5..323a13992 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -354,8 +354,8 @@ void cProtocol125::SendEntityLook(const cEntity & a_Entity)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_LOOK);
WriteInt (a_Entity.GetUniqueID());
- WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@@ -423,8 +423,8 @@ void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
WriteByte(a_RelX);
WriteByte(a_RelY);
WriteByte(a_RelZ);
- WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@@ -664,7 +664,7 @@ void cProtocol125::SendPlayerMoveLook(void)
WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosZ());
- WriteFloat ((float)(Player->GetRotation()));
+ WriteFloat ((float)(Player->GetYaw()));
WriteFloat ((float)(Player->GetPitch()));
WriteBool (Player->IsOnGround());
Flush();
@@ -694,8 +694,8 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
- WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
Flush();
}
@@ -864,7 +864,7 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
- WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
+ WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256));
WriteInt (a_VehicleSubType);
if (a_VehicleSubType != 0)
{
@@ -897,7 +897,7 @@ void cProtocol125::SendTeleportEntity(const cEntity & a_Entity)
WriteInt ((int)(floor(a_Entity.GetPosX() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosY() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosZ() * 32)));
- WriteByte ((char)((a_Entity.GetRotation() / 360.f) * 256));
+ WriteByte ((char)((a_Entity.GetYaw() / 360.f) * 256));
WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 302d1298c..29fbb4bba 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -367,8 +367,8 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
- WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
// Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata:
WriteByte (0); // Index 0, byte (flags)
@@ -421,8 +421,8 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
WriteInt (a_Mob.GetUniqueID());
WriteByte (a_Mob.GetMobType());
WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
- WriteByte ((Byte)((a_Mob.GetRotation() / 360.f) * 256));
- WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
+ WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256));
+ WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256));
WriteShort ((short)(a_Mob.GetSpeedX() * 400));
WriteShort ((short)(a_Mob.GetSpeedY() * 400));
diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp
index 926fe6ee8..127ce9d4b 100644
--- a/src/Protocol/Protocol14x.cpp
+++ b/src/Protocol/Protocol14x.cpp
@@ -250,7 +250,7 @@ void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
- WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
+ WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256));
WriteInt (a_VehicleSubType);
if (a_VehicleSubType != 0)
{
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 93621fcc2..5b3a79555 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -1040,7 +1040,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (!HandlePacket(bb, PacketType))
{
// Unknown packet, already been reported, but without the length. Log the length here:
- LOGWARNING("Unhandled packet: type 0x%x, length %u", PacketType, PacketLen);
+ LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen);
#ifdef _DEBUG
// Dump the packet contents into the log:
@@ -1059,8 +1059,8 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (bb.GetReadableSpace() != 1)
{
// Read more or less than packet length, report as error
- LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x. Read %u bytes, packet contained %u bytes",
- PacketType, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
+ LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes",
+ PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
);
ASSERT(!"Read wrong number of bytes!");
m_Client->PacketError(PacketType);
@@ -1128,9 +1128,26 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
}
break;
}
+ default:
+ {
+ // Received a packet in an unknown state, report:
+ LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
+
+ // Cannot kick the client - we don't know this state and thus the packet number for the kick packet
+
+ // Switch to a state when all further packets are silently ignored:
+ m_State = 255;
+ return false;
+ }
+ case 255:
+ {
+ // This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
+ // Do not output anything (the caller will do that for us), just return failure
+ return false;
+ }
} // switch (m_State)
- // Unknown packet type, report to the client:
+ // Unknown packet type, report to the ClientHandle:
m_Client->PacketUnknown(a_PacketType);
return false;
}
@@ -1668,7 +1685,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
return;
}
- // Load enchantments from the NBT:
+ // Load enchantments and custom display names from the NBT data:
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
{
if (
@@ -1681,6 +1698,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
a_Item.m_Enchantments.ParseFromNBT(NBT, tag);
}
+ else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag
+ {
+ for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
+ {
+ if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ {
+ a_Item.m_CustomName = NBT.GetString(displaytag);
+ }
+ else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ {
+ AString Lore;
+
+ for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ {
+ AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
+ }
+
+ a_Item.m_Lore = Lore;
+ }
+ }
+ }
}
}
@@ -1732,16 +1770,45 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
WriteByte (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
- if (a_Item.m_Enchantments.IsEmpty())
+ if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
{
WriteShort(-1);
return;
}
- // Send the enchantments:
+ // Send the enchantments and custom names:
cFastNBTWriter Writer;
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
- a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
+ 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);
+ }
+ if (!a_Item.IsBothNameAndLoreEmpty())
+ {
+ Writer.BeginCompound("display");
+ if (!a_Item.IsCustomNameEmpty())
+ {
+ Writer.AddString("Name", a_Item.m_CustomName.c_str());
+ }
+ if (!a_Item.IsLoreEmpty())
+ {
+ Writer.BeginList("Lore", TAG_String);
+
+ AStringVector Decls = StringSplit(a_Item.m_Lore, "`");
+ for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ // The decl is empty (two `s), ignore
+ continue;
+ }
+ Writer.AddString("", itr->c_str());
+ }
+
+ Writer.EndList();
+ }
+ Writer.EndCompound();
+ }
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
@@ -1823,8 +1890,23 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteInt(1); // Shaking direction, doesn't seem to affect anything
WriteByte(0x73);
WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer
-
- if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
+
+ if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
+ {
+ cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
+ if (!RideableMinecart.GetContent().IsEmpty())
+ {
+ WriteByte(0x54);
+ int Content = RideableMinecart.GetContent().m_ItemType;
+ Content |= RideableMinecart.GetContent().m_ItemDamage << 8;
+ WriteInt(Content);
+ WriteByte(0x55);
+ WriteInt(RideableMinecart.GetBlockHeight());
+ WriteByte(0x56);
+ WriteByte(1);
+ }
+ }
+ else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
{
WriteByte(0x10);
WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0);
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/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index a721e6b7e..bfcad3d92 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -85,10 +85,10 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
{
if (DraggingItem.m_ItemType <= 0) // Empty-handed?
{
+ DraggingItem = Slot.CopyOne(); // Obtain copy of slot to preserve lore, enchantments, etc.
+
DraggingItem.m_ItemCount = (char)(((float)Slot.m_ItemCount) / 2.f + 0.5f);
Slot.m_ItemCount -= DraggingItem.m_ItemCount;
- DraggingItem.m_ItemType = Slot.m_ItemType;
- DraggingItem.m_ItemDamage = Slot.m_ItemDamage;
if (Slot.m_ItemCount <= 0)
{
@@ -101,9 +101,12 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
cItemHandler * Handler = ItemHandler(Slot.m_ItemType);
if ((DraggingItem.m_ItemCount > 0) && (Slot.m_ItemCount < Handler->GetMaxStackSize()))
{
- Slot.m_ItemType = DraggingItem.m_ItemType;
- Slot.m_ItemCount++;
- Slot.m_ItemDamage = DraggingItem.m_ItemDamage;
+ char OldSlotCount = Slot.m_ItemCount;
+
+ Slot = DraggingItem.CopyOne(); // See above
+ OldSlotCount++;
+ Slot.m_ItemCount = OldSlotCount;
+
DraggingItem.m_ItemCount--;
}
if (DraggingItem.m_ItemCount <= 0)
@@ -226,7 +229,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_
for (int i = 0; i < m_NumSlots; i++)
{
const cItem * Slot = GetSlot(i, a_Player);
- if (!Slot->IsStackableWith(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
+ if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
{
// Different items
continue;
@@ -265,7 +268,7 @@ bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool
for (int i = 0; i < NumSlots; i++)
{
const cItem & SlotItem = *GetSlot(i, a_Player);
- if (!SlotItem.IsStackableWith(a_Dragging))
+ if (!SlotItem.IsEqual(a_Dragging))
{
continue;
}
@@ -908,7 +911,7 @@ void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End)
} // for i - itr->second[]
double vX = 0, vY = 0, vZ = 0;
- EulerToVector(-a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY);
+ EulerToVector(-a_Player.GetYaw(), a_Player.GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because player created
}
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index ee75921d1..3ffeff7a0 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -642,7 +642,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int
Area->SetSlot(LocalSlotNum, a_Player, ToStore);
NumDistributed += ToStore.m_ItemCount;
}
- else if (AtSlot.IsStackableWith(a_Item))
+ else if (AtSlot.IsEqual(a_Item))
{
// Occupied, add and cap at MaxStack:
int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount);
diff --git a/src/World.cpp b/src/World.cpp
index 2b85e4b58..8e7b6171c 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -16,6 +16,7 @@
// Entities (except mobs):
#include "Entities/ExpOrb.h"
#include "Entities/FallingBlock.h"
+#include "Entities/Minecart.h"
#include "Entities/Pickup.h"
#include "Entities/Player.h"
#include "Entities/TNTEntity.h"
@@ -230,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),
@@ -511,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);
@@ -584,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();
@@ -1146,6 +1149,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);
@@ -1673,6 +1685,29 @@ int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
+int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight)
+{
+ cMinecart * Minecart;
+ switch (a_MinecartType)
+ {
+ case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break;
+ case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break;
+ case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break;
+ case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break;
+ case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break;
+ default:
+ {
+ return -1;
+ }
+ } // switch (a_MinecartType)
+ Minecart->Initialize(this);
+ return Minecart->GetUniqueID();
+}
+
+
+
+
+
void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff)
{
UNUSED(a_InitialVelocityCoeff);
@@ -2740,9 +2775,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 6ddb3ec86..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;
@@ -374,6 +375,9 @@ public:
/// 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.
+ 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.
int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
@@ -463,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
@@ -678,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 e5043de1f..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();
}
@@ -257,7 +273,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C
m_Writer.AddDouble("", a_Entity->GetSpeedZ());
m_Writer.EndList();
m_Writer.BeginList("Rotation", TAG_Double);
- m_Writer.AddDouble("", a_Entity->GetRotation());
+ m_Writer.AddDouble("", a_Entity->GetYaw());
m_Writer.AddDouble("", a_Entity->GetPitch());
m_Writer.EndList();
}
@@ -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 8605930b6..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)
@@ -1150,7 +1193,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN
void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cEmptyMinecart> Minecart(new cEmptyMinecart(0, 0, 0));
+ std::auto_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@@ -1891,7 +1934,7 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
{
return false;
}
- a_Entity.SetRotation(Rotation[0]);
+ a_Entity.SetYaw(Rotation[0]);
a_Entity.SetRoll (Rotation[1]);
return true;
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;
diff --git a/src/main.cpp b/src/main.cpp
index 0620e0f0e..340149e0b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -47,9 +47,20 @@ void NonCtrlHandler(int a_Signal)
case SIGSEGV:
{
std::signal(SIGSEGV, SIG_DFL);
- LOGWARN("Segmentation fault; MCServer has crashed :(");
+ LOGERROR(" D: | MCServer has encountered an error and needs to close");
+ LOGERROR("Details | SIGSEGV: Segmentation fault");
exit(EXIT_FAILURE);
}
+ case SIGABRT:
+ #ifdef SIGABRT_COMPAT
+ case SIGABRT_COMPAT:
+ #endif
+ {
+ std::signal(a_Signal, SIG_DFL);
+ LOGERROR(" D: | MCServer has encountered an error and needs to close");
+ LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
+ break;
+ }
case SIGTERM:
{
std::signal(SIGTERM, SIG_IGN); // Server is shutting down, wait for it...