summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTiger Wang <ziwei.tiger@hotmail.co.uk>2014-06-24 22:15:48 +0200
committerTiger Wang <ziwei.tiger@hotmail.co.uk>2014-06-24 22:15:48 +0200
commitbd5df3d3b975c448e3d8f4227d86a742d0ad3b12 (patch)
tree30193169848d8ea39e2e5a423bd9e1a8e189c5f6
parentConforms to standards (diff)
parentMerge pull request #1125 from Howaner/Entities (diff)
downloadcuberite-bd5df3d3b975c448e3d8f4227d86a742d0ad3b12.tar
cuberite-bd5df3d3b975c448e3d8f4227d86a742d0ad3b12.tar.gz
cuberite-bd5df3d3b975c448e3d8f4227d86a742d0ad3b12.tar.bz2
cuberite-bd5df3d3b975c448e3d8f4227d86a742d0ad3b12.tar.lz
cuberite-bd5df3d3b975c448e3d8f4227d86a742d0ad3b12.tar.xz
cuberite-bd5df3d3b975c448e3d8f4227d86a742d0ad3b12.tar.zst
cuberite-bd5df3d3b975c448e3d8f4227d86a742d0ad3b12.zip
Diffstat (limited to '')
-rw-r--r--CONTRIBUTORS4
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua3
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua4
-rw-r--r--src/BlockEntities/ChestEntity.cpp13
-rw-r--r--src/BlockEntities/HopperEntity.cpp77
-rw-r--r--src/BlockInfo.cpp21
-rw-r--r--src/Blocks/BlockDoor.cpp7
-rw-r--r--src/Blocks/BlockFenceGate.h1
-rw-r--r--src/Blocks/BlockHandler.cpp89
-rw-r--r--src/Blocks/BlockLever.h11
-rw-r--r--src/Blocks/BlockSign.h6
-rw-r--r--src/Blocks/BlockSlab.h15
-rw-r--r--src/Chunk.cpp6
-rw-r--r--src/ClientHandle.cpp29
-rw-r--r--src/ClientHandle.h11
-rw-r--r--src/Generating/Prefab.cpp11
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp63
-rw-r--r--src/VoronoiMap.cpp4
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp3
-rw-r--r--src/WorldStorage/WSSAnvil.cpp21
20 files changed, 297 insertions, 102 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 50c8dbfb8..09515aa6b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,6 +1,6 @@
Many people have contributed to MCServer, and this list attempts to broadcast at least some of them.
-BasedDoge - Donated AlchemistVillage prefabs
+BasedDoge (Donated AlchemistVillage prefabs)
bearbin (Alexander Harkness)
derouinw
Diusrex
@@ -27,6 +27,6 @@ tonibm19
UltraCoderRU
worktycho
xoft
-Yeeeeezus - Donated AlchemistVillage prefabs
+Yeeeeezus (Donated AlchemistVillage prefabs)
Please add yourself to this list if you contribute to MCServer.
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 19ca971e2..06e333cf9 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -523,13 +523,16 @@ end
Functions =
{
+ GenerateOfflineUUID = { Params = "Username", Return = "string", Notes = "(STATIC) Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. Returns a 36-char UUID (with dashes)." },
GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." },
GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" },
GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
+ GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data." },
GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" },
GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" },
HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
+ IsUUIDOnline = { Params = "UUID", Return = "bool", Notes = "(STATIC) Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID. We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart. Accepts both 32-char and 36-char UUIDs (with and without dashes). If the string given is not a valid UUID, returns false."},
Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" },
SendPluginMessage = { Params = "Channel, Message", Return = "", Notes = "Sends the plugin message on the specified channel." },
SetLocale = { Params = "Locale", Return = "", Notes = "Sets the locale that MCServer keeps on record. Initially the locale is initialized in protocol handshake, this function allows plugins to override the stored value (but only server-side and only until the user disconnects)." },
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index 534426d25..deb6a720b 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -346,7 +346,7 @@ end
function OnUsingBlazeRod(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, CursorY, CursorZ)
-- Magic rod of query: show block types and metas for both neighbors of the pointed face
- local Type, Meta, Valid = Player:GetWorld():GetBlockTypeMeta(BlockX, BlockY, BlockZ, Type, Meta);
+ local Valid, Type, Meta = Player:GetWorld():GetBlockTypeMeta(BlockX, BlockY, BlockZ);
if (Type == E_BLOCK_AIR) then
Player:SendMessage(cChatColor.LightGray .. "Block {" .. BlockX .. ", " .. BlockY .. ", " .. BlockZ .. "}: air:" .. Meta);
@@ -356,7 +356,7 @@ function OnUsingBlazeRod(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cur
end
local X, Y, Z = AddFaceDirection(BlockX, BlockY, BlockZ, BlockFace);
- Valid, Type, Meta = Player:GetWorld():GetBlockTypeMeta(X, Y, Z, Type, Meta);
+ Valid, Type, Meta = Player:GetWorld():GetBlockTypeMeta(X, Y, Z);
if (Type == E_BLOCK_AIR) then
Player:SendMessage(cChatColor.LightGray .. "Block {" .. X .. ", " .. Y .. ", " .. Z .. "}: air:" .. Meta);
else
diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp
index dfbe6ae87..cb9cc89bf 100644
--- a/src/BlockEntities/ChestEntity.cpp
+++ b/src/BlockEntities/ChestEntity.cpp
@@ -122,6 +122,13 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
void cChestEntity::OpenNewWindow(void)
{
+ // TODO: cats are an obstruction
+ if ((GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())))
+ {
+ // Obstruction, don't open
+ return;
+ }
+
// Callback for opening together with neighbor chest:
class cOpenDouble :
public cChestCallback
@@ -135,6 +142,12 @@ void cChestEntity::OpenNewWindow(void)
virtual bool Item(cChestEntity * a_Chest) override
{
+ if ((a_Chest->GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(a_Chest->GetWorld()->GetBlock(a_Chest->GetPosX(), a_Chest->GetPosY() + 1, a_Chest->GetPosZ())))
+ {
+ // Obstruction, don't open
+ return false;
+ }
+
// The primary chest should eb the one with lesser X or Z coord:
cChestEntity * Primary = a_Chest;
cChestEntity * Secondary = m_ThisChest;
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index 7f001c739..5856f20d1 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -294,23 +294,24 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
return false;
}
- int bx, by, bz;
+ // Get the coords of the block where to output items:
+ int OutX, OutY, OutZ;
NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ);
- if (!GetOutputBlockPos(Meta, bx, by, bz))
+ if (!GetOutputBlockPos(Meta, OutX, OutY, OutZ))
{
// Not attached to another container
return false;
}
- if (by < 0)
+ if (OutY < 0)
{
// Cannot output below the zero-th block level
return false;
}
// Convert coords to relative:
- int rx = bx - a_Chunk.GetPosX() * cChunkDef::Width;
- int rz = bz - a_Chunk.GetPosZ() * cChunkDef::Width;
- cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(rx, rz);
+ int OutRelX = OutX - a_Chunk.GetPosX() * cChunkDef::Width;
+ int OutRelZ = OutZ - a_Chunk.GetPosZ() * cChunkDef::Width;
+ cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(OutRelX, OutRelZ);
if (DestChunk == NULL)
{
// The destination chunk has been unloaded, don't tick
@@ -319,26 +320,32 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
// Call proper moving function, based on the blocktype present at the coords:
bool res = false;
- switch (DestChunk->GetBlock(rx, by, rz))
+ switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ))
{
case E_BLOCK_CHEST:
{
// Chests have special handling because of double-chests
- res = MoveItemsToChest(*DestChunk, bx, by, bz);
+ res = MoveItemsToChest(*DestChunk, OutX, OutY, OutZ);
break;
}
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_FURNACE:
{
// Furnaces have special handling because of the direction-to-slot relation
- res = MoveItemsToFurnace(*DestChunk, bx, by, bz, Meta);
+ res = MoveItemsToFurnace(*DestChunk, OutX, OutY, OutZ, Meta);
break;
}
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_HOPPER:
{
- res = MoveItemsToGrid(*(cBlockEntityWithItems *)DestChunk->GetBlockEntity(bx, by, bz));
+ cBlockEntityWithItems * BlockEntity = (cBlockEntityWithItems *)DestChunk->GetBlockEntity(OutX, OutY, OutZ);
+ if (BlockEntity == NULL)
+ {
+ LOGWARNING("%s: A block entity was not found where expected at {%d, %d, %d}", __FUNCTION__, OutX, OutY, OutZ);
+ return false;
+ }
+ res = MoveItemsToGrid(*BlockEntity);
break;
}
}
@@ -359,7 +366,13 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
/// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
{
- if (MoveItemsFromGrid(*(cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)))
+ cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
+ if (Chest == NULL)
+ {
+ LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ);
+ return false;
+ }
+ if (MoveItemsFromGrid(*Chest))
{
// Moved the item from the chest directly above the hopper
return true;
@@ -389,9 +402,17 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
{
continue;
}
- if (MoveItemsFromGrid(*(cChestEntity *)Neighbor->GetBlockEntity(x, m_PosY, z)))
+ Chest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
+ if (Chest == NULL)
{
- return true;
+ LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
+ }
+ else
+ {
+ if (MoveItemsFromGrid(*Chest))
+ {
+ return true;
+ }
}
return false;
}
@@ -408,7 +429,11 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
bool cHopperEntity::MoveItemsFromFurnace(cChunk & a_Chunk)
{
cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
- ASSERT(Furnace != NULL);
+ if (Furnace == NULL)
+ {
+ LOGWARNING("%s: A furnace entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ);
+ return false;
+ }
// Try move from the output slot:
if (MoveItemsFromSlot(*Furnace, cFurnaceEntity::fsOutput, true))
@@ -517,7 +542,13 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl
bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ)
{
// Try the chest directly connected to the hopper:
- if (MoveItemsToGrid(*(cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)))
+ cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ);
+ if (Chest == NULL)
+ {
+ LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, a_BlockX, a_BlockY, a_BlockZ);
+ return false;
+ }
+ if (MoveItemsToGrid(*Chest))
{
return true;
}
@@ -534,19 +565,27 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
{0, 1},
{0, -1},
} ;
+ int RelX = a_BlockX - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = a_BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width;
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
{
- int x = m_RelX + Coords[i].x;
- int z = m_RelZ + Coords[i].z;
+ int x = RelX + Coords[i].x;
+ int z = RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if (
(Neighbor == NULL) ||
- (Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
+ (Neighbor->GetBlock(x, a_BlockY, z) != E_BLOCK_CHEST)
)
{
continue;
}
- if (MoveItemsToGrid(*(cChestEntity *)Neighbor->GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)))
+ Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z);
+ if (Chest == NULL)
+ {
+ LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d} (%d, %d)", __FUNCTION__, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z, x, z);
+ continue;
+ }
+ if (MoveItemsToGrid(*Chest))
{
return true;
}
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 32fdec905..b084d0915 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -9,6 +9,7 @@
cBlockInfo cBlockInfo::ms_Info[256];
+static bool g_IsBlockInfoInitialized = false;
@@ -43,6 +44,11 @@ cBlockInfo::~cBlockInfo()
cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
{
+ if (!g_IsBlockInfoInitialized)
+ {
+ cBlockInfo::Initialize();
+ g_IsBlockInfoInitialized = true;
+ }
return ms_Info[a_Type];
}
@@ -448,18 +454,3 @@ void cBlockInfo::Initialize(void)
-
-// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
-class cBlockInfoInitializer
-{
-public:
- cBlockInfoInitializer(void)
- {
- cBlockInfo::Initialize();
- }
-} BlockInfoInitializer;
-
-
-
-
-
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index fb2d6f2dc..934a01994 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -45,9 +45,16 @@ void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldIn
void cBlockDoorHandler::OnUse(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)
{
+ UNUSED(a_WorldInterface);
+ UNUSED(a_BlockFace);
+ UNUSED(a_CursorX);
+ UNUSED(a_CursorY);
+ UNUSED(a_CursorZ);
+
if (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR)
{
ChangeDoor(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ a_Player->GetWorld()->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
}
}
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index e202c6610..e992870d4 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -45,6 +45,7 @@ public:
// Standing aside - use last direction
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, OldMetaData);
}
+ a_Player->GetWorld()->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
}
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index a7b89fcb7..405c9bf43 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -85,6 +85,91 @@
+/*
+// Tests the meta rotation and mirroring.
+// Note that the cMetaRotator needs to have its assert paths disabled for this test to work!
+static class cBlockHandlerRotationTester
+{
+public:
+ cBlockHandlerRotationTester(void)
+ {
+ printf("Performing block handlers test...\n");
+ for (BLOCKTYPE Type = 0; Type < E_BLOCK_MAX_TYPE_ID; Type++)
+ {
+ cBlockHandler * Handler = cBlockInfo::GetHandler(Type);
+ if (Handler == NULL)
+ {
+ printf("NULL handler for block type %d!\n", Type);
+ continue;
+ }
+ AString BlockName = ItemTypeToString(Type);
+ for (NIBBLETYPE Meta = 0; Meta < 16; Meta++)
+ {
+ // Test the CW / CCW rotations:
+ NIBBLETYPE TestMeta;
+ TestMeta = Handler->MetaRotateCW(Handler->MetaRotateCW(Handler->MetaRotateCW(Handler->MetaRotateCW(Meta))));
+ if (TestMeta != Meta)
+ {
+ // 4 CW rotations should produce no change in the meta
+ printf("Handler for blocktype %d (%s) fails CW 4-rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+ TestMeta = Handler->MetaRotateCCW(Handler->MetaRotateCCW(Handler->MetaRotateCCW(Handler->MetaRotateCCW(Meta))));
+ if (TestMeta != Meta)
+ {
+ // 4 CCW rotations should produce no change in the meta
+ printf("Handler for blocktype %d (%s) fails CCW 4-rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+ TestMeta = Handler->MetaRotateCCW(Handler->MetaRotateCW(Meta));
+ if (TestMeta != Meta)
+ {
+ // CCW rotation of a CW rotation should produce no change in the meta
+ printf("Handler for blocktype %d (%s) fails CCW(CW) rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+ TestMeta = Handler->MetaRotateCW(Handler->MetaRotateCCW(Meta));
+ if (TestMeta != Meta)
+ {
+ // CW rotation of a CCW rotation should produce no change in the meta
+ printf("Handler for blocktype %d (%s) fails CW(CCW) rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+
+ // Test the mirroring:
+ TestMeta = Handler->MetaMirrorXY(Handler->MetaMirrorXY(Meta));
+ if (TestMeta != Meta)
+ {
+ // Double-mirroring should produce the same meta:
+ printf("Handler for blocktype %d (%s) fails XY mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+ TestMeta = Handler->MetaMirrorXZ(Handler->MetaMirrorXZ(Meta));
+ if (TestMeta != Meta)
+ {
+ // Double-mirroring should produce the same meta:
+ printf("Handler for blocktype %d (%s) fails XZ mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+ TestMeta = Handler->MetaMirrorYZ(Handler->MetaMirrorYZ(Meta));
+ if (TestMeta != Meta)
+ {
+ // Double-mirroring should produce the same meta:
+ printf("Handler for blocktype %d (%s) fails YZ mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+
+ // Test mirror-rotating:
+ TestMeta = Handler->MetaRotateCW(Handler->MetaRotateCW(Handler->MetaMirrorXY(Handler->MetaMirrorYZ(Meta))));
+ if (TestMeta != Meta)
+ {
+ // 2 CW rotations should be the same as XY, YZ mirroring:
+ printf("Handler for blocktype %d (%s) fails rotation-mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
+ }
+ }
+ } // for Type
+ printf("Block handlers test complete.\n");
+ }
+} g_BlockHandlerRotationTester;
+//*/
+
+
+
+
+
cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{
switch(a_BlockType)
@@ -175,7 +260,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_QUARTZ_BLOCK: return new cBlockQuartzHandler (a_BlockType);
case E_BLOCK_QUARTZ_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_RAIL: return new cBlockRailHandler (a_BlockType);
- case E_BLOCK_REDSTONE_LAMP_ON: return new cBlockRedstoneLampHandler (a_BlockType); // We need this to change pickups to an off lamp; else 1.7+ clients crash
+ case E_BLOCK_REDSTONE_LAMP_ON: return new cBlockRedstoneLampHandler (a_BlockType);
case E_BLOCK_REDSTONE_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_REDSTONE_ORE_GLOWING: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_REDSTONE_REPEATER_OFF: return new cBlockRedstoneRepeaterHandler(a_BlockType);
@@ -207,7 +292,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
- case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType);
+ case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType); // TODO: This needs a special handler
case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType);
case E_BLOCK_WOODEN_BUTTON: return new cBlockButtonHandler (a_BlockType);
case E_BLOCK_WOODEN_DOOR: return new cBlockDoorHandler (a_BlockType);
diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h
index ad2ae29e5..f1d3ff6d2 100644
--- a/src/Blocks/BlockLever.h
+++ b/src/Blocks/BlockLever.h
@@ -7,12 +7,13 @@
class cBlockLeverHandler :
- public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>
+ public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>
{
- typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false> super;
+ typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false> super;
+
public:
- cBlockLeverHandler(BLOCKTYPE a_BlockType)
- : cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>(a_BlockType)
+ cBlockLeverHandler(BLOCKTYPE a_BlockType) :
+ super(a_BlockType)
{
}
@@ -132,7 +133,7 @@ public:
case 0x05: return 0x06; // Ground rotation
case 0x06: return 0x05;
- default: return super::MetaRotateCCW(a_Meta); // Wall Rotation
+ default: return super::MetaRotateCW(a_Meta); // Wall Rotation
}
}
} ;
diff --git a/src/Blocks/BlockSign.h b/src/Blocks/BlockSign.h
index 9d6fede21..f5630bdb0 100644
--- a/src/Blocks/BlockSign.h
+++ b/src/Blocks/BlockSign.h
@@ -75,13 +75,13 @@ public:
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
- return (++a_Meta) & 0x0F;
+ return (a_Meta + 4) & 0x0f;
}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
- return (--a_Meta) & 0x0F;
+ return (a_Meta + 12) & 0x0f;
}
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
@@ -90,7 +90,7 @@ public:
// There are 16 meta values which correspond to different directions.
// These values are equated to angles on a circle; 0x08 = 180 degrees.
- return (a_Meta < 0x08) ? 0x08 + a_Meta : 0x08 - a_Meta;
+ return (a_Meta < 0x08) ? (0x08 + a_Meta) : (0x08 - a_Meta);
}
diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h
index f3f2366fd..6c861be86 100644
--- a/src/Blocks/BlockSlab.h
+++ b/src/Blocks/BlockSlab.h
@@ -124,6 +124,12 @@ public:
return E_BLOCK_AIR;
}
+
+ virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
+ {
+ // Toggle the 4th bit - up / down:
+ return (a_Meta ^ 0x08);
+ }
} ;
@@ -167,15 +173,6 @@ public:
ASSERT(!"Unhandled double slab type!");
return "";
}
-
-
- virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
- {
- NIBBLETYPE OtherMeta = a_Meta & 0x07; // Contains unrelated meta data.
-
- // 8th bit is up/down. 1 right-side-up, 0 is up-side-down.
- return (a_Meta & 0x08) ? 0x00 + OtherMeta : 0x01 + OtherMeta;
- }
} ;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 0b8e2d1a9..2e14cf368 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -1616,6 +1616,12 @@ void cChunk::AddBlockEntity(cBlockEntity * a_BlockEntity)
cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ)
{
+ // Check that the query coords are within chunk bounds:
+ ASSERT(a_BlockX >= m_PosX * cChunkDef::Width);
+ ASSERT(a_BlockX < m_PosX * cChunkDef::Width + cChunkDef::Width);
+ ASSERT(a_BlockZ >= m_PosZ * cChunkDef::Width);
+ ASSERT(a_BlockZ < m_PosZ * cChunkDef::Width + cChunkDef::Width);
+
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{
if (
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 1c6c989c5..a39a87077 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -231,6 +231,9 @@ AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessage
AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
{
+ // Online UUIDs are always version 4 (random)
+ // We use Version 3 (MD5 hash) UUIDs for the offline UUIDs
+ // This guarantees that they will never collide with an online UUID and can be distinguished.
// Proper format for a version 3 UUID is:
// xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B
@@ -253,6 +256,32 @@ AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
+bool cClientHandle::IsUUIDOnline(const AString & a_UUID)
+{
+ // Online UUIDs are always version 4 (random)
+ // We use Version 3 (MD5 hash) UUIDs for the offline UUIDs
+ // This guarantees that they will never collide with an online UUID and can be distinguished.
+ // The version-specifying char is at pos #12 of raw UUID, pos #14 in dashed-UUID.
+ switch (a_UUID.size())
+ {
+ case 32:
+ {
+ // This is the UUID format without dashes, the version char is at pos #12:
+ return (a_UUID[12] == '4');
+ }
+ case 36:
+ {
+ // This is the UUID format with dashes, the version char is at pos #14:
+ return (a_UUID[14] == '4');
+ }
+ }
+ return false;
+}
+
+
+
+
+
void cClientHandle::Kick(const AString & a_Reason)
{
if (m_State >= csAuthenticating) // Don't log pings
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 99d10c3aa..d6e086bd2 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -63,7 +63,7 @@ public:
const AString & GetIPString(void) const { return m_IPString; }
- cPlayer* GetPlayer() { return m_Player; } // tolua_export
+ cPlayer * GetPlayer(void) { return m_Player; } // tolua_export
const AString & GetUUID(void) const { return m_UUID; } // tolua_export
void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
@@ -76,9 +76,16 @@ public:
/** Generates an UUID based on the player name provided.
This is used for the offline (non-auth) mode, when there's no UUID source.
- Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */
+ Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
+ Returns a 36-char UUID (with dashes). */
static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export
+ /** Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID.
+ We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart.
+ Accepts both 32-char and 36-char UUIDs (with and without dashes).
+ If the string given is not a valid UUID, returns false. */
+ static bool IsUUIDOnline(const AString & a_UUID); // tolua_export
+
/** Formats the type of message with the proper color and prefix for sending to the client. **/
static AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData);
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
index 2ab1455b9..7d876909a 100644
--- a/src/Generating/Prefab.cpp
+++ b/src/Generating/Prefab.cpp
@@ -211,6 +211,17 @@ void cPrefab::Draw(cChunkDesc & a_Dest, const Vector3i & a_Placement, int a_NumR
int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
const cBlockArea & Image = m_BlockArea[a_NumRotations];
+
+ // If the placement is outside this chunk, bail out:
+ if (
+ (Placement.x > cChunkDef::Width) || (Placement.x + Image.GetSizeX() < 0) ||
+ (Placement.z > cChunkDef::Width) || (Placement.z + Image.GetSizeZ() < 0)
+ )
+ {
+ return;
+ }
+
+ // Write the image:
a_Dest.WriteBlockArea(Image, Placement.x, Placement.y, Placement.z, m_MergeStrategy);
// If requested, draw the floor (from the bottom of the prefab down to the nearest non-air)
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index 183c527ca..10446a879 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -59,21 +59,20 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
int RelZ = 0;
BLOCKTYPE Block;
NIBBLETYPE Meta;
- cChunk * Chunk;
+ cChunk * OtherChunk = a_Chunk;
if (a_OtherChunk != NULL)
{
RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width;
RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
- Chunk = a_OtherChunk;
+ OtherChunk = a_OtherChunk;
}
else
{
RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
- Chunk = a_Chunk;
}
// Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid
@@ -92,7 +91,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = PoweredBlocks->erase(itr);
- Chunk->SetIsRedstoneDirty(true);
+ a_Chunk->SetIsRedstoneDirty(true);
+ OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (
@@ -107,21 +107,23 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = PoweredBlocks->erase(itr);
- Chunk->SetIsRedstoneDirty(true);
+ a_Chunk->SetIsRedstoneDirty(true);
+ OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
{
- if (!m_World.IsChunkLighted(Chunk->GetPosX(), Chunk->GetPosZ()))
+ if (!m_World.IsChunkLighted(OtherChunk->GetPosX(), OtherChunk->GetPosZ()))
{
- m_World.QueueLightChunk(Chunk->GetPosX(), Chunk->GetPosZ());
+ m_World.QueueLightChunk(OtherChunk->GetPosX(), OtherChunk->GetPosZ());
}
else
{
- if (Chunk->GetTimeAlteredLight(Chunk->GetSkyLight(RelX, a_BlockY + 1, RelZ)) <= 7)
+ if (OtherChunk->GetTimeAlteredLight(OtherChunk->GetSkyLight(RelX, a_BlockY + 1, RelZ)) <= 7)
{
itr = PoweredBlocks->erase(itr);
- Chunk->SetIsRedstoneDirty(true);
+ a_Chunk->SetIsRedstoneDirty(true);
+ OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@@ -139,7 +141,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
- Chunk->SetIsRedstoneDirty(true);
+ a_Chunk->SetIsRedstoneDirty(true);
+ OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (
@@ -153,7 +156,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
- Chunk->SetIsRedstoneDirty(true);
+ a_Chunk->SetIsRedstoneDirty(true);
+ OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@@ -163,7 +167,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
- Chunk->SetIsRedstoneDirty(true);
+ a_Chunk->SetIsRedstoneDirty(true);
+ OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@@ -343,6 +348,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
case E_BLOCK_REDSTONE_REPEATER_ON:
{
HandleRedstoneRepeater(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
+ break;
}
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
@@ -520,8 +526,11 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBl
{
if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
{
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4);
- m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ if ((MetaData & 0x4) == 0)
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ }
SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
}
}
@@ -529,8 +538,11 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBl
{
if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
{
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & 0xFFFFFFFB);
- m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ if ((MetaData & 0x4) != 0)
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & ~0x04);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ }
SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
}
}
@@ -758,7 +770,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int
void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
{
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); itr++)
+ for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();)
{
if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
@@ -804,7 +816,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
{
m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta);
}
- m_RepeatersDelayList->erase(itr);
+ itr = m_RepeatersDelayList->erase(itr);
}
else
{
@@ -813,6 +825,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
// I am confounded to say why. Perhaps optimisation failure.
LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
itr->a_ElapsedTicks++;
+ itr++;
}
}
}
@@ -1072,19 +1085,17 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBl
void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- int a_ChunkX, a_ChunkZ;
- cChunkDef::BlockToChunk(a_RelBlockX, a_RelBlockZ, a_ChunkX, a_ChunkZ);
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX, BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ int ChunkX, ChunkZ;
+ cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
- if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ))
+ if (!m_World.IsChunkLighted(ChunkX, ChunkZ))
{
- m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
+ m_World.QueueLightChunk(ChunkX, ChunkZ);
}
else
{
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- NIBBLETYPE SkyLight = m_Chunk->GetTimeAlteredLight(m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ));
- if (SkyLight > 8)
+ if (m_Chunk->GetTimeAlteredLight(m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ)) > 8)
{
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
}
diff --git a/src/VoronoiMap.cpp b/src/VoronoiMap.cpp
index 9c3ca7e65..5efd09c01 100644
--- a/src/VoronoiMap.cpp
+++ b/src/VoronoiMap.cpp
@@ -14,7 +14,9 @@ cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
m_Noise1(a_Seed + 1),
m_Noise2(a_Seed + 2),
m_Noise3(a_Seed + 3),
- m_CellSize(a_CellSize)
+ m_CellSize(a_CellSize),
+ m_CurrentCellX(9999999), // Cell coords that are definitely out of the range for normal generator, so that the first query will overwrite them
+ m_CurrentCellZ(9999999)
{
}
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index d058a4583..93ade6448 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -345,6 +345,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C
m_Writer.AddDouble("", a_Entity->GetYaw());
m_Writer.AddDouble("", a_Entity->GetPitch());
m_Writer.EndList();
+ m_Writer.AddShort("Health", a_Entity->GetHealth());
}
@@ -576,7 +577,6 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
m_Writer.BeginCompound("");
AddBasicEntity(a_Pickup, "Item");
AddItem(a_Pickup->GetItem(), -1, "Item");
- m_Writer.AddShort("Health", (Int16)(unsigned char)a_Pickup->GetHealth());
m_Writer.AddShort("Age", (Int16)a_Pickup->GetAge());
m_Writer.EndCompound();
}
@@ -679,7 +679,6 @@ void cNBTChunkSerializer::AddExpOrbEntity(cExpOrb * a_ExpOrb)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_ExpOrb, "XPOrb");
- m_Writer.AddShort("Health", (Int16)(unsigned char)a_ExpOrb->GetHealth());
m_Writer.AddShort("Age", (Int16)a_ExpOrb->GetAge());
m_Writer.AddShort("Value", (Int16)a_ExpOrb->GetReward());
m_Writer.EndCompound();
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index a3259b769..f714c0414 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -1461,13 +1461,6 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
-
- // Load health:
- int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
- if (Health > 0)
- {
- Pickup->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
- }
// Load age:
int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
@@ -1513,13 +1506,6 @@ void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a
return;
}
- // Load Health:
- int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
- if (Health > 0)
- {
- ExpOrb->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
- }
-
// Load Age:
int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
if (Age > 0)
@@ -2437,6 +2423,13 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
}
a_Entity.SetYaw(Rotation[0]);
a_Entity.SetRoll(Rotation[1]);
+
+ // Load health:
+ int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
+ if (Health > 0)
+ {
+ a_Entity.SetHealth(a_NBT.GetShort(Health));
+ }
return true;
}