summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua2
-rw-r--r--src/Bindings/ManualBindings.cpp135
-rw-r--r--src/BlockArea.h6
-rw-r--r--src/BlockEntities/BlockEntity.cpp2
-rw-r--r--src/BlockEntities/MobHeadEntity.cpp108
-rw-r--r--src/BlockEntities/MobHeadEntity.h79
-rw-r--r--src/Blocks/BlockHandler.cpp2
-rw-r--r--src/Blocks/BlockMobHead.h69
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Chunk.cpp35
-rw-r--r--src/Chunk.h7
-rw-r--r--src/ChunkMap.cpp18
-rw-r--r--src/ChunkMap.h5
-rw-r--r--src/Defines.h37
-rw-r--r--src/Items/ItemHandler.cpp2
-rw-r--r--src/Items/ItemMobHead.h42
-rw-r--r--src/Protocol/Protocol17x.cpp15
-rw-r--r--src/World.cpp9
-rw-r--r--src/World.h5
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp26
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--src/WorldStorage/WSSAnvil.cpp40
-rw-r--r--src/WorldStorage/WSSAnvil.h1
23 files changed, 612 insertions, 36 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index fd4b1d947..73bb5c7fb 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -118,7 +118,7 @@ g_APIDesc =
GetRelBlockMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the block meta at the specified relative coords" },
GetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified relative coords" },
GetRelBlockType = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified relative coords" },
- GetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the block type and meta at the specified relative coords" },
+ GetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified relative coords" },
GetSizeX = { Params = "", Return = "number", Notes = "Returns the size of the held data in the x-axis" },
GetSizeY = { Params = "", Return = "number", Notes = "Returns the size of the held data in the y-axis" },
GetSizeZ = { Params = "", Return = "number", Notes = "Returns the size of the held data in the z-axis" },
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 2a7631120..c220e5e0a 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -22,6 +22,7 @@
#include "../BlockEntities/FurnaceEntity.h"
#include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/NoteEntity.h"
+#include "../BlockEntities/MobHeadEntity.h"
#include "md5/md5.h"
#include "../LineBlockTracer.h"
#include "../WorldStorage/SchematicFileSerializer.h"
@@ -212,7 +213,7 @@ static int tolua_DoWith(lua_State* tolua_S)
return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs);
}
- Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0);
+ Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, NULL);
const char * ItemName = tolua_tocppstring(tolua_S, 2, "");
if ((ItemName == NULL) || (ItemName[0] == 0))
@@ -306,7 +307,7 @@ static int tolua_DoWithID(lua_State* tolua_S)
return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs);
}
- Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, 0);
+ Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, NULL);
int ItemID = (int)tolua_tonumber(tolua_S, 2, 0);
if (!lua_isfunction(tolua_S, 3))
@@ -396,7 +397,7 @@ static int tolua_DoWithXYZ(lua_State* tolua_S)
return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 4 or 5 arguments, got %i", NumArgs);
}
- Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0);
+ Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, NULL);
if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3) || !lua_isnumber(tolua_S, 4))
{
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3");
@@ -490,7 +491,7 @@ static int tolua_ForEachInChunk(lua_State* tolua_S)
return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 3 or 4 arguments, got %i", NumArgs);
}
- Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0);
+ Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, NULL);
if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3))
{
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1 and #2");
@@ -584,7 +585,7 @@ static int tolua_ForEach(lua_State * tolua_S)
return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 1 or 2 arguments, got %i", NumArgs);
}
- Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0);
+ Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
@@ -681,7 +682,7 @@ static int tolua_cWorld_GetBlockInfo(lua_State * tolua_S)
else
#endif
{
- cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0);
+ cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL);
int BlockX = (int) tolua_tonumber (tolua_S, 2, 0);
int BlockY = (int) tolua_tonumber (tolua_S, 3, 0);
int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0);
@@ -736,7 +737,7 @@ static int tolua_cWorld_GetBlockTypeMeta(lua_State * tolua_S)
else
#endif
{
- cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0);
+ cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL);
int BlockX = (int) tolua_tonumber (tolua_S, 2, 0);
int BlockY = (int) tolua_tonumber (tolua_S, 3, 0);
int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0);
@@ -788,7 +789,7 @@ static int tolua_cWorld_GetSignLines(lua_State * tolua_S)
else
#endif
{
- cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0);
+ cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL);
int BlockX = (int) tolua_tonumber (tolua_S, 2, 0);
int BlockY = (int) tolua_tonumber (tolua_S, 3, 0);
int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0);
@@ -846,7 +847,7 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
else
#endif
{
- cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0);
+ cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL);
int BlockX = (int) tolua_tonumber (tolua_S, 2, 0);
int BlockY = (int) tolua_tonumber (tolua_S, 3, 0);
int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0);
@@ -895,7 +896,7 @@ static int tolua_cWorld_TryGetHeight(lua_State * tolua_S)
else
#endif
{
- cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0);
+ cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL);
int BlockX = (int) tolua_tonumber (tolua_S, 2, 0);
int BlockZ = (int) tolua_tonumber (tolua_S, 3, 0);
#ifndef TOLUA_RELEASE
@@ -967,7 +968,7 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S)
}
// Retrieve the args:
- cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, 0);
+ cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
@@ -1065,7 +1066,7 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S)
{
- cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, 0);
+ cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, NULL);
const cPluginManager::PluginMap & AllPlugins = self->GetAllPlugins();
@@ -1289,7 +1290,7 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S)
return 0;
}
- cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, 0);
+ cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
LOGWARN("Error in function call 'ForEachCommand': Not called on an object instance");
@@ -1364,7 +1365,7 @@ static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S)
return 0;
}
- cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, 0);
+ cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
LOGWARN("Error in function call 'ForEachConsoleCommand': Not called on an object instance");
@@ -1686,7 +1687,7 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
{
- cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0);
+ cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
const cPlayer::GroupList & AllGroups = self->GetGroups();
@@ -1711,7 +1712,7 @@ static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
static int tolua_cPlayer_GetResolvedPermissions(lua_State* tolua_S)
{
- cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0);
+ cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
cPlayer::StringList AllPermissions = self->GetResolvedPermissions();
@@ -1824,7 +1825,7 @@ static int tolua_SetObjectCallback(lua_State * tolua_S)
static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S)
{
- cPluginLua * self = (cPluginLua *)tolua_tousertype(tolua_S,1,0);
+ cPluginLua * self = (cPluginLua *)tolua_tousertype(tolua_S, 1, NULL);
tolua_Error tolua_err;
tolua_err.array = 0;
@@ -1868,7 +1869,7 @@ static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S)
static int tolua_cPluginLua_AddTab(lua_State* tolua_S)
{
- cPluginLua * self = (cPluginLua *) tolua_tousertype(tolua_S, 1, 0);
+ cPluginLua * self = (cPluginLua *) tolua_tousertype(tolua_S, 1, NULL);
LOGWARN("WARNING: Using deprecated function AddTab()! Use AddWebTab() instead. (plugin \"%s\" in folder \"%s\")",
self->GetName().c_str(), self->GetDirectory().c_str()
);
@@ -1888,7 +1889,7 @@ static int tolua_cPlugin_Call(lua_State * tolua_S)
L.LogStackTrace();
// Retrieve the params: plugin and the function name to call
- cPluginLua * TargetPlugin = (cPluginLua *) tolua_tousertype(tolua_S, 1, 0);
+ cPluginLua * TargetPlugin = (cPluginLua *) tolua_tousertype(tolua_S, 1, NULL);
AString FunctionName = tolua_tostring(tolua_S, 2, "");
// Call the function:
@@ -1941,7 +1942,7 @@ static int tolua_push_StringStringMap(lua_State* tolua_S, std::map< std::string,
static int tolua_get_HTTPRequest_Params(lua_State* tolua_S)
{
- HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S,1,0);
+ HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, NULL);
return tolua_push_StringStringMap(tolua_S, self->Params);
}
@@ -1951,7 +1952,7 @@ static int tolua_get_HTTPRequest_Params(lua_State* tolua_S)
static int tolua_get_HTTPRequest_PostParams(lua_State* tolua_S)
{
- HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S,1,0);
+ HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, NULL);
return tolua_push_StringStringMap(tolua_S, self->PostParams);
}
@@ -1961,7 +1962,7 @@ static int tolua_get_HTTPRequest_PostParams(lua_State* tolua_S)
static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S)
{
- HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S,1,0);
+ HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, NULL);
std::map< std::string, HTTPFormData >& FormData = self->FormData;
lua_newtable(tolua_S);
@@ -1984,7 +1985,7 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S)
static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
{
- cWebAdmin* self = (cWebAdmin*) tolua_tousertype(tolua_S,1,0);
+ cWebAdmin* self = (cWebAdmin*) tolua_tousertype(tolua_S, 1, NULL);
const cWebAdmin::PluginList & AllPlugins = self->GetPlugins();
@@ -2009,7 +2010,7 @@ static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S)
{
- cWebPlugin* self = (cWebPlugin*) tolua_tousertype(tolua_S,1,0);
+ cWebPlugin* self = (cWebPlugin*) tolua_tousertype(tolua_S, 1, NULL);
const cWebPlugin::TabNameList & TabNames = self->GetTabNames();
@@ -2076,7 +2077,7 @@ static int Lua_ItemGrid_GetSlotCoords(lua_State * L)
}
{
- const cItemGrid * self = (const cItemGrid *)tolua_tousertype(L, 1, 0);
+ const cItemGrid * self = (const cItemGrid *)tolua_tousertype(L, 1, NULL);
int SlotNum = (int)tolua_tonumber(L, 2, 0);
if (self == NULL)
{
@@ -2288,7 +2289,7 @@ static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S)
{
return 0;
}
- cHopperEntity * self = (cHopperEntity *)tolua_tousertype(tolua_S, 1, 0);
+ cHopperEntity * self = (cHopperEntity *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cHopperEntity::GetOutputBlockPos()'", NULL);
@@ -2314,6 +2315,76 @@ static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S)
+static int tolua_cBlockArea_GetBlockTypeMeta(lua_State * tolua_S)
+{
+ // function cBlockArea::GetBlockTypeMeta()
+ // Exported manually because tolua generates extra input params for the outputs
+
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cBlockArea") ||
+ !L.CheckParamNumber (2, 4)
+ )
+ {
+ return 0;
+ }
+
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", NULL);
+ return 0;
+ }
+ int BlockX = (int)tolua_tonumber(tolua_S, 2, 0);
+ int BlockY = (int)tolua_tonumber(tolua_S, 3, 0);
+ int BlockZ = (int)tolua_tonumber(tolua_S, 4, 0);
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ self->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta);
+ tolua_pushnumber(tolua_S, BlockType);
+ tolua_pushnumber(tolua_S, BlockMeta);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cBlockArea_GetRelBlockTypeMeta(lua_State * tolua_S)
+{
+ // function cBlockArea::GetRelBlockTypeMeta()
+ // Exported manually because tolua generates extra input params for the outputs
+
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cBlockArea") ||
+ !L.CheckParamNumber (2, 4)
+ )
+ {
+ return 0;
+ }
+
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", NULL);
+ return 0;
+ }
+ int BlockX = (int)tolua_tonumber(tolua_S, 2, 0);
+ int BlockY = (int)tolua_tonumber(tolua_S, 3, 0);
+ int BlockZ = (int)tolua_tonumber(tolua_S, 4, 0);
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ self->GetRelBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta);
+ tolua_pushnumber(tolua_S, BlockType);
+ tolua_pushnumber(tolua_S, BlockMeta);
+ return 2;
+}
+
+
+
+
+
static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::LoadFromSchematicFile
@@ -2327,7 +2398,7 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
{
return 0;
}
- cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, 0);
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL);
@@ -2343,6 +2414,7 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
+
static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::SaveToSchematicFile
@@ -2356,7 +2428,7 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
{
return 0;
}
- cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, 0);
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL);
@@ -2370,6 +2442,8 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
+
+
void ManualBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, NULL);
@@ -2386,8 +2460,10 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cBlockArea");
+ tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
+ tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
- tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
+ tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cHopperEntity");
@@ -2416,6 +2492,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
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, "DoWithMobHeadBlockAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadBlockAt>);
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>);
diff --git a/src/BlockArea.h b/src/BlockArea.h
index 59bc0f241..b4a161f32 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -184,9 +184,15 @@ public:
void SetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+
+ // tolua_end
+
+ // These need manual exporting, tolua generates the binding as requiring 2 extra input params
void GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
void GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
+ // tolua_begin
+
int GetSizeX(void) const { return m_SizeX; }
int GetSizeY(void) const { return m_SizeY; }
int GetSizeZ(void) const { return m_SizeZ; }
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index 97b5c1a66..57ad83de9 100644
--- a/src/BlockEntities/BlockEntity.cpp
+++ b/src/BlockEntities/BlockEntity.cpp
@@ -15,6 +15,7 @@
#include "JukeboxEntity.h"
#include "NoteEntity.h"
#include "SignEntity.h"
+#include "MobHeadEntity.h"
@@ -29,6 +30,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
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_HEAD: return new cMobHeadEntity (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);
diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp
new file mode 100644
index 000000000..c0a1781f6
--- /dev/null
+++ b/src/BlockEntities/MobHeadEntity.cpp
@@ -0,0 +1,108 @@
+
+// MobHeadEntity.cpp
+
+// Implements the cMobHeadEntity class representing a single skull/head in the world
+
+#include "Globals.h"
+#include "json/json.h"
+#include "MobHeadEntity.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
+ super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World),
+ m_Owner("")
+{
+}
+
+
+
+
+
+void cMobHeadEntity::UsedBy(cPlayer * a_Player)
+{
+ UNUSED(a_Player);
+}
+
+
+
+
+
+void cMobHeadEntity::SetType(const eMobHeadType & a_Type)
+{
+ if ((!m_Owner.empty()) && (a_Type != SKULL_TYPE_PLAYER))
+ {
+ m_Owner = "";
+ }
+ m_Type = a_Type;
+}
+
+
+
+
+
+void cMobHeadEntity::SetRotation(eMobHeadRotation a_Rotation)
+{
+ m_Rotation = a_Rotation;
+}
+
+
+
+
+
+void cMobHeadEntity::SetOwner(const AString & a_Owner)
+{
+ if ((a_Owner.length() > 16) || (m_Type != SKULL_TYPE_PLAYER))
+ {
+ return;
+ }
+ m_Owner = a_Owner;
+}
+
+
+
+
+
+void cMobHeadEntity::SendTo(cClientHandle & a_Client)
+{
+ a_Client.SendUpdateBlockEntity(*this);
+}
+
+
+
+
+
+bool cMobHeadEntity::LoadFromJson(const Json::Value & a_Value)
+{
+ m_PosX = a_Value.get("x", 0).asInt();
+ m_PosY = a_Value.get("y", 0).asInt();
+ m_PosZ = a_Value.get("z", 0).asInt();
+
+ m_Type = static_cast<eMobHeadType>(a_Value.get("Type", 0).asInt());
+ m_Rotation = static_cast<eMobHeadRotation>(a_Value.get("Rotation", 0).asInt());
+ m_Owner = a_Value.get("Owner", "").asString();
+
+ return true;
+}
+
+
+
+
+
+void cMobHeadEntity::SaveToJson(Json::Value & a_Value)
+{
+ a_Value["x"] = m_PosX;
+ a_Value["y"] = m_PosY;
+ a_Value["z"] = m_PosZ;
+
+ a_Value["Type"] = m_Type;
+ a_Value["Rotation"] = m_Rotation;
+ a_Value["Owner"] = m_Owner;
+}
+
+
+
+
diff --git a/src/BlockEntities/MobHeadEntity.h b/src/BlockEntities/MobHeadEntity.h
new file mode 100644
index 000000000..367eb15e7
--- /dev/null
+++ b/src/BlockEntities/MobHeadEntity.h
@@ -0,0 +1,79 @@
+// MobHeadEntity.h
+
+// Declares the cMobHeadEntity class representing a single skull/head in the world
+
+
+
+
+
+#pragma once
+
+#include "BlockEntity.h"
+
+
+
+
+
+namespace Json
+{
+ class Value;
+}
+
+
+
+
+
+// tolua_begin
+
+class cMobHeadEntity :
+ public cBlockEntity
+{
+ typedef cBlockEntity super;
+
+public:
+
+ // tolua_end
+
+ /** Creates a new mob head entity at the specified block coords. a_World may be NULL */
+ cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+
+ bool LoadFromJson( const Json::Value& a_Value );
+ virtual void SaveToJson(Json::Value& a_Value ) override;
+
+ // tolua_begin
+
+ /** Set the Type */
+ void SetType(const eMobHeadType & a_SkullType);
+
+ /** Set the Rotation */
+ void SetRotation(eMobHeadRotation a_Rotation);
+
+ /** Set the Player Name for Mobheads with Player type */
+ void SetOwner(const AString & a_Owner);
+
+ /** Get the Type */
+ eMobHeadType GetType(void) const { return m_Type; }
+
+ /** Get the Rotation */
+ eMobHeadRotation GetRotation(void) const { return m_Rotation; }
+
+ /** Get the setted Player Name */
+ AString GetOwner(void) const { return m_Owner; }
+
+ // tolua_end
+
+ virtual void UsedBy(cPlayer * a_Player) override;
+ virtual void SendTo(cClientHandle & a_Client) override;
+
+ static const char * GetClassStatic(void) { return "cMobHeadEntity"; }
+
+private:
+
+ eMobHeadType m_Type;
+ eMobHeadRotation m_Rotation;
+ AString m_Owner;
+} ; // tolua_export
+
+
+
+
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index fa9e797a2..834727c9a 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -34,6 +34,7 @@
#include "BlockGlass.h"
#include "BlockGlowstone.h"
#include "BlockGravel.h"
+#include "BlockMobHead.h"
#include "BlockHopper.h"
#include "BlockIce.h"
#include "BlockLadder.h"
@@ -149,6 +150,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_GRASS: return new cBlockDirtHandler (a_BlockType);
case E_BLOCK_GRAVEL: return new cBlockGravelHandler (a_BlockType);
case E_BLOCK_HAY_BALE: return new cBlockSidewaysHandler (a_BlockType);
+ case E_BLOCK_HEAD: return new cBlockMobHeadHandler (a_BlockType);
case E_BLOCK_HOPPER: return new cBlockHopperHandler (a_BlockType);
case E_BLOCK_ICE: return new cBlockIceHandler (a_BlockType);
case E_BLOCK_INACTIVE_COMPARATOR: return new cBlockComparatorHandler (a_BlockType);
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
new file mode 100644
index 000000000..6a00c3acd
--- /dev/null
+++ b/src/Blocks/BlockMobHead.h
@@ -0,0 +1,69 @@
+
+#pragma once
+
+#include "BlockEntity.h"
+#include "../BlockEntities/MobHeadEntity.h"
+
+
+
+
+
+class cBlockMobHeadHandler :
+ public cBlockEntityHandler
+{
+public:
+ cBlockMobHeadHandler(BLOCKTYPE a_BlockType)
+ : cBlockEntityHandler(a_BlockType)
+ {
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0));
+ }
+
+ virtual void OnPlacedByPlayer(
+ cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
+ ) override
+ {
+ class cCallback : public cMobHeadBlockCallback
+ {
+ cPlayer * m_Player;
+ NIBBLETYPE m_OldBlockMeta;
+ NIBBLETYPE m_NewBlockMeta;
+
+ virtual bool Item (cMobHeadEntity * a_MobHeadEntity)
+ {
+ int Rotation = 0;
+ if (m_NewBlockMeta == 1)
+ {
+ Rotation = (int) floor(m_Player->GetYaw() * 16.0F / 360.0F + 0.5) & 0xF;
+ }
+
+ a_MobHeadEntity->SetType(static_cast<eMobHeadType>(m_OldBlockMeta));
+ a_MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation));
+ return false;
+ }
+
+ public:
+ cCallback (cPlayer * a_Player, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) :
+ m_Player(a_Player),
+ m_OldBlockMeta(a_OldBlockMeta),
+ m_NewBlockMeta(a_NewBlockMeta)
+ {}
+ };
+ cCallback Callback(a_Player, a_BlockMeta, static_cast<NIBBLETYPE>(a_BlockFace));
+
+ a_BlockMeta = a_BlockFace;
+ cWorld * World = (cWorld *) &a_WorldInterface;
+ World->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
+ }
+} ;
+
+
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 16bdad14e..387556775 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -39,6 +39,7 @@ if (NOT MSVC)
BlockEntities/JukeboxEntity.h
BlockEntities/NoteEntity.h
BlockEntities/SignEntity.h
+ BlockEntities/MobHeadEntity.h
BlockID.h
BoundingBox.h
ChatColor.h
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 0587beb9c..4f301c209 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -19,6 +19,7 @@
#include "BlockEntities/JukeboxEntity.h"
#include "BlockEntities/NoteEntity.h"
#include "BlockEntities/SignEntity.h"
+#include "BlockEntities/MobHeadEntity.h"
#include "Entities/Pickup.h"
#include "Item.h"
#include "Noise.h"
@@ -1314,6 +1315,7 @@ void cChunk::CreateBlockEntities(void)
case E_BLOCK_HOPPER:
case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN:
+ case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX:
{
@@ -1442,6 +1444,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
case E_BLOCK_HOPPER:
case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN:
+ case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX:
{
@@ -2341,6 +2344,38 @@ bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
+bool cChunk::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & 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_HEAD)
+ {
+ // 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((cMobHeadEntity *)*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 682ec6170..1b7a6fa07 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -31,6 +31,7 @@ class cChestEntity;
class cDispenserEntity;
class cFurnaceEntity;
class cNoteEntity;
+class cMobHeadEntity;
class cBlockArea;
class cPawn;
class cPickup;
@@ -47,6 +48,7 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
@@ -249,7 +251,10 @@ public:
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);
+ bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback);
+
+ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob header block at those coords or callback returns true, returns true if found */
+ bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & 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 01195e8bc..fbb8706e0 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -2178,6 +2178,24 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
+bool cChunkMap::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & 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->DoWithMobHeadBlockAt(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)
{
int ChunkX, ChunkZ;
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 9f0dd087e..9df68c403 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -25,6 +25,7 @@ class cDropSpenserEntity;
class cFurnaceEntity;
class cNoteEntity;
class cCommandBlockEntity;
+class cMobHeadEntity;
class cPawn;
class cPickup;
class cChunkDataSerializer;
@@ -43,6 +44,7 @@ typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
typedef cItemCallback<cChunk> cChunkCallback;
@@ -254,6 +256,9 @@ public:
/** 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
+ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
+ bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & 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/Defines.h b/src/Defines.h
index f33d1ae56..ba2866f83 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -174,6 +174,43 @@ enum eWeather
+enum eMobHeadType
+{
+ SKULL_TYPE_SKELETON = 0,
+ SKULL_TYPE_WITHER = 1,
+ SKULL_TYPE_ZOMBIE = 2,
+ SKULL_TYPE_PLAYER = 3,
+ SKULL_TYPE_CREEPER = 4,
+} ;
+
+
+
+
+
+enum eMobHeadRotation
+{
+ SKULL_ROTATION_NORTH = 0,
+ SKULL_ROTATION_NORTH_NORTH_EAST = 1,
+ SKULL_ROTATION_NORTH_EAST = 2,
+ SKULL_ROTATION_EAST_NORTH_EAST = 3,
+ SKULL_ROTATION_EAST = 4,
+ SKULL_ROTATION_EAST_SOUTH_EAST = 5,
+ SKULL_ROTATION_SOUTH_EAST = 6,
+ SKULL_ROTATION_SOUTH_SOUTH_EAST = 7,
+ SKULL_ROTATION_SOUTH = 8,
+ SKULL_ROTATION_SOUTH_SOUTH_WEST = 9,
+ SKULL_ROTATION_SOUTH_WEST = 10,
+ SKULL_ROTATION_WEST_SOUTH_WEST = 11,
+ SKULL_ROTATION_WEST = 12,
+ SKULL_ROTATION_WEST_NORTH_WEST = 13,
+ SKULL_ROTATION_NORTH_WEST = 14,
+ SKULL_ROTATION_NORTH_NORTH_WEST = 15,
+} ;
+
+
+
+
+
inline const char * ClickActionToString(eClickAction a_ClickAction)
{
switch (a_ClickAction)
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 945f84b9c..e9bb616a6 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -37,6 +37,7 @@
#include "ItemShears.h"
#include "ItemShovel.h"
#include "ItemSign.h"
+#include "ItemMobHead.h"
#include "ItemSpawnEgg.h"
#include "ItemSugarcane.h"
#include "ItemSword.h"
@@ -114,6 +115,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType);
case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType);
case E_ITEM_SIGN: return new cItemSignHandler(a_ItemType);
+ case E_ITEM_HEAD: return new cItemMobHeadHandler(a_ItemType);
case E_ITEM_SNOWBALL: return new cItemSnowballHandler();
case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType);
case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType);
diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h
new file mode 100644
index 000000000..5ae040282
--- /dev/null
+++ b/src/Items/ItemMobHead.h
@@ -0,0 +1,42 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+
+
+
+
+
+class cItemMobHeadHandler :
+ public cItemHandler
+{
+public:
+ cItemMobHeadHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_HEAD;
+ a_BlockMeta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage & 0x0f);
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 0c569c07c..aaf8830cd 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -28,6 +28,7 @@ Implements the 1.7.x protocol classes:
#include "../Mobs/IncludeAllMonsters.h"
#include "../UI/Window.h"
#include "../BlockEntities/CommandBlockEntity.h"
+#include "../BlockEntities/MobHeadEntity.h"
#include "../CompositeChat.h"
@@ -1058,6 +1059,7 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
{
case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing
case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text
+ case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity
default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
}
Pkt.WriteByte(Action);
@@ -2285,6 +2287,19 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
}
break;
}
+ case E_BLOCK_HEAD:
+ {
+ cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity;
+
+ Writer.AddInt("x", MobHeadEntity.GetPosX());
+ Writer.AddInt("y", MobHeadEntity.GetPosY());
+ Writer.AddInt("z", MobHeadEntity.GetPosZ());
+ Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF);
+ Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF);
+ Writer.AddString("ExtraType", MobHeadEntity.GetOwner().c_str());
+ Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
+ break;
+ }
default: break;
}
diff --git a/src/World.cpp b/src/World.cpp
index 313a8d7fa..42c286c46 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1165,6 +1165,15 @@ bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
+bool cWorld::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback)
+{
+ return m_ChunkMap->DoWithMobHeadBlockAt(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);
diff --git a/src/World.h b/src/World.h
index d79de3b87..5c18c5d23 100644
--- a/src/World.h
+++ b/src/World.h
@@ -45,6 +45,7 @@ class cChestEntity;
class cDispenserEntity;
class cFurnaceEntity;
class cNoteEntity;
+class cMobHeadEntity;
class cMobCensus;
class cCompositeChat;
class cCuboid;
@@ -58,6 +59,7 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
@@ -519,6 +521,9 @@ public:
/** 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
+ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
+ bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & 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
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index c7aaa2633..2a1eda523 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -19,6 +19,7 @@
#include "../BlockEntities/JukeboxEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
+#include "../BlockEntities/MobHeadEntity.h"
#include "../Entities/Entity.h"
#include "../Entities/FallingBlock.h"
@@ -248,11 +249,25 @@ void cNBTChunkSerializer::AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock
void cNBTChunkSerializer::AddSignEntity(cSignEntity * a_Sign)
{
m_Writer.BeginCompound("");
- AddBasicTileEntity(a_Sign, "Sign");
- m_Writer.AddString("Text1", a_Sign->GetLine(0));
- m_Writer.AddString("Text2", a_Sign->GetLine(1));
- m_Writer.AddString("Text3", a_Sign->GetLine(2));
- m_Writer.AddString("Text4", a_Sign->GetLine(3));
+ AddBasicTileEntity(a_Sign, "Sign");
+ m_Writer.AddString("Text1", a_Sign->GetLine(0));
+ m_Writer.AddString("Text2", a_Sign->GetLine(1));
+ m_Writer.AddString("Text3", a_Sign->GetLine(2));
+ m_Writer.AddString("Text4", a_Sign->GetLine(3));
+ m_Writer.EndCompound();
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddMobHeadEntity(cMobHeadEntity * a_MobHead)
+{
+ m_Writer.BeginCompound("");
+ AddBasicTileEntity(a_MobHead, "Skull");
+ m_Writer.AddByte ("SkullType", a_MobHead->GetType() & 0xFF);
+ m_Writer.AddByte ("Rot", a_MobHead->GetRotation() & 0xFF);
+ m_Writer.AddString("ExtraType", a_MobHead->GetOwner());
m_Writer.EndCompound();
}
@@ -668,6 +683,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
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_HEAD: AddMobHeadEntity ((cMobHeadEntity *) 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;
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 245b68063..5f9e16ed1 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -29,6 +29,7 @@ class cHopperEntity;
class cJukeboxEntity;
class cNoteEntity;
class cSignEntity;
+class cMobHeadEntity;
class cFallingBlock;
class cMinecart;
class cMinecartWithChest;
@@ -93,6 +94,7 @@ protected:
void AddJukeboxEntity (cJukeboxEntity * a_Jukebox);
void AddNoteEntity (cNoteEntity * a_Note);
void AddSignEntity (cSignEntity * a_Sign);
+ void AddMobHeadEntity (cMobHeadEntity * a_MobHead);
void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock);
// Entities:
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index e95813a3c..d4490c7fe 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -24,6 +24,7 @@
#include "../BlockEntities/JukeboxEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
+#include "../BlockEntities/MobHeadEntity.h"
#include "../Mobs/Monster.h"
@@ -597,6 +598,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
{
LoadSignFromNBT(a_BlockEntities, a_NBT, Child);
}
+ else if (strncmp(a_NBT.GetData(sID), "Skull", a_NBT.GetDataLength(sID)) == 0)
+ {
+ LoadMobHeadFromNBT(a_BlockEntities, a_NBT, Child);
+ }
else if (strncmp(a_NBT.GetData(sID), "Trap", a_NBT.GetDataLength(sID)) == 0)
{
LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child);
@@ -927,6 +932,41 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse
+void cWSSAnvil::LoadMobHeadFromNBT(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<cMobHeadEntity> MobHead(new cMobHeadEntity(x, y, z, m_World));
+
+ int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType");
+ if (currentLine >= 0)
+ {
+ MobHead->SetType(static_cast<eMobHeadType>(a_NBT.GetByte(currentLine)));
+ }
+
+ currentLine = a_NBT.FindChildByName(a_TagIdx, "Rot");
+ if (currentLine >= 0)
+ {
+ MobHead->SetRotation(static_cast<eMobHeadRotation>(a_NBT.GetByte(currentLine)));
+ }
+
+ currentLine = a_NBT.FindChildByName(a_TagIdx, "ExtraType");
+ if (currentLine >= 0)
+ {
+ MobHead->SetOwner(a_NBT.GetString(currentLine));
+ }
+
+ a_BlockEntities.push_back(MobHead.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 5093ad083..541371560 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -139,6 +139,7 @@ protected:
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 LoadMobHeadFromNBT (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);