summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MCServer/Plugins/@EnableMobDebug.lua29
-rw-r--r--MCServer/Plugins/InfoReg.lua4
-rw-r--r--src/BlockEntities/DispenserEntity.cpp6
-rw-r--r--src/BlockInfo.cpp1
-rw-r--r--src/Blocks/BlockAnvil.h63
-rw-r--r--src/Blocks/BlockBed.cpp73
-rw-r--r--src/Blocks/BlockCake.h55
-rw-r--r--src/Blocks/BlockHandler.cpp4
-rw-r--r--src/Blocks/BlockLeaves.h1
-rw-r--r--src/Blocks/BlockMushroom.h1
-rw-r--r--src/Blocks/BlockVine.h2
-rw-r--r--src/Blocks/BroadcastInterface.h5
-rw-r--r--src/Blocks/WorldInterface.h8
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/ChunkMap.cpp7
-rw-r--r--src/Defines.h26
-rw-r--r--src/Entities/ExpOrb.cpp26
-rw-r--r--src/Entities/ExpOrb.h23
-rw-r--r--src/Entities/HangingEntity.cpp53
-rw-r--r--src/Entities/HangingEntity.h49
-rw-r--r--src/Entities/ItemFrame.cpp39
-rw-r--r--src/Entities/ItemFrame.h22
-rw-r--r--src/Entities/Pickup.cpp2
-rw-r--r--src/Entities/Pickup.h23
-rw-r--r--src/Entities/Player.h17
-rw-r--r--src/Items/ItemCake.h41
-rw-r--r--src/Items/ItemHandler.cpp5
-rw-r--r--src/Items/ItemItemFrame.h6
-rw-r--r--src/Items/ItemLighter.h22
-rw-r--r--src/Items/ItemShears.h5
-rw-r--r--src/MobSpawner.cpp2
-rw-r--r--src/World.h8
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp59
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h6
-rw-r--r--src/WorldStorage/WSSAnvil.cpp201
-rw-r--r--src/WorldStorage/WSSAnvil.h6
36 files changed, 742 insertions, 161 deletions
diff --git a/MCServer/Plugins/@EnableMobDebug.lua b/MCServer/Plugins/@EnableMobDebug.lua
deleted file mode 100644
index 48d4c36b7..000000000
--- a/MCServer/Plugins/@EnableMobDebug.lua
+++ /dev/null
@@ -1,29 +0,0 @@
-
--- @EnableMobDebug.lua
-
--- Enables the MobDebug debugger, used by ZeroBrane Studio, for a plugin
--- Needs to be named with a @ at the start so that it's loaded as the first file of the plugin
-
---[[
-Usage:
-Copy this file to your plugin's folder when you want to debug that plugin
-You should neither check this file into the plugin's version control system,
-nor distribute it in the final release.
---]]
-
-
-
-
-
--- Try to load the debugger, be silent about failures:
-local IsSuccess, MobDebug = pcall(require, "mobdebug")
-if (IsSuccess) then
- MobDebug.start()
-
- -- The debugger will automatically put a breakpoint on this line, use this opportunity to set more breakpoints in your code
- LOG(cPluginManager:GetCurrentPlugin():GetName() .. ": MobDebug enabled")
-end
-
-
-
-
diff --git a/MCServer/Plugins/InfoReg.lua b/MCServer/Plugins/InfoReg.lua
index 1cf68dbed..b3717884a 100644
--- a/MCServer/Plugins/InfoReg.lua
+++ b/MCServer/Plugins/InfoReg.lua
@@ -59,13 +59,13 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
return true;
end
- -- Check if the handler is valid:
+ -- If the handler is not valid, check the next sublevel:
if (Subcommand.Handler == nil) then
if (Subcommand.Subcommands == nil) then
LOG("Cannot find handler for command " .. a_CmdString .. " " .. Verb);
return false;
end
- ListSubcommands(a_Player, Subcommand.Subcommands, a_CmdString .. " " .. Verb);
+ MultiCommandHandler(a_Split, a_Player, a_CmdString .. " " .. Verb, Subcommand, a_Level + 1);
return true;
end
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index cbfbb1b6a..e03bf776d 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -138,6 +138,12 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
break;
}
+ case E_ITEM_FIRE_CHARGE:
+ {
+ // TODO: Spawn fireball entity
+ break;
+ }
+
default:
{
DropFromSlot(a_Chunk, a_SlotNum);
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index d1ecfdf7e..7d438ba3e 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -93,6 +93,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h
new file mode 100644
index 000000000..9f5f84be0
--- /dev/null
+++ b/src/Blocks/BlockAnvil.h
@@ -0,0 +1,63 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cBlockAnvilHandler :
+ public cBlockHandler
+{
+public:
+ cBlockAnvilHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cChunkInterface & a_ChunkInterface, 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 = m_BlockType;
+
+ int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3;
+ int RawMeta = a_BlockMeta >> 2;
+
+ Direction++;
+ Direction %= 4;
+ switch (Direction)
+ {
+ case 0: a_BlockMeta = 0x2 | RawMeta << 2; break;
+ case 1: a_BlockMeta = 0x3 | RawMeta << 2; break;
+ case 2: a_BlockMeta = 0x0 | RawMeta << 2; break;
+ case 3: a_BlockMeta = 0x1 | RawMeta << 2; break;
+ default:
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool IsUseable() override
+ {
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index 3dad4feba..6a3c6a55b 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -51,6 +51,49 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
+class cTimeFastForwardTester :
+ public cPlayerListCallback
+{
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ if (!a_Player->IsInBed())
+ {
+ return true;
+ }
+
+ return false;
+ }
+};
+
+
+
+
+
+class cPlayerBedStateUnsetter :
+ public cPlayerListCallback
+{
+public:
+ cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) :
+ m_Position(a_Position), m_WorldInterface(a_WorldInterface)
+ {
+ }
+
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ a_Player->SetIsInBed(false);
+ m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2);
+ return false;
+ }
+
+private:
+ Vector3i m_Position;
+ cWorldInterface & m_WorldInterface;
+};
+
+
+
+
+
void cBlockBedHandler::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)
{
if (a_WorldInterface.GetDimension() != dimOverworld)
@@ -69,6 +112,8 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
}
else
{
+ Vector3i PillowDirection(0, 0, 0);
+
if (Meta & 0x8)
{
// Is pillow
@@ -77,16 +122,30 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
else
{
// Is foot end
- Vector3i Direction = MetaDataToDirection( Meta & 0x7 );
- if (a_ChunkInterface.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
+ VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken
+
+ PillowDirection = MetaDataToDirection(Meta & 0x7);
+ if (a_ChunkInterface.GetBlock(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
{
- a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z);
+ a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z);
}
}
- a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, (Meta | (1 << 2)));
- }
-
- } else {
+
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit
+ a_Player->SetIsInBed(true);
+
+ cTimeFastForwardTester Tester;
+ if (a_WorldInterface.ForEachPlayer(Tester))
+ {
+ cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface);
+ a_WorldInterface.ForEachPlayer(Unsetter);
+ a_WorldInterface.SetTimeOfDay(0);
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0xB); // Where 0xB = 1011, and zero is to make sure 'occupied' bit is always unset
+ }
+ }
+ }
+ else
+ {
a_Player->SendMessageFailure("You can only sleep at night");
}
}
diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h
new file mode 100644
index 000000000..36e133388
--- /dev/null
+++ b/src/Blocks/BlockCake.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockCakeHandler :
+ public cBlockHandler
+{
+public:
+ cBlockCakeHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual void 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) override
+ {
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ if (!a_Player->Feed(2, 0.1))
+ {
+ return;
+ }
+
+ if (Meta >= 5)
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+ else
+ {
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta + 1);
+ }
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ // Give nothing
+ }
+
+ virtual bool IsUseable(void) override
+ {
+ return true;
+ }
+
+ virtual const char * GetStepSound(void) override
+ {
+ return "step.cloth";
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index aa97b2ca9..4f74e2f45 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -6,10 +6,12 @@
#include "../Root.h"
#include "../Bindings/PluginManager.h"
#include "../Chunk.h"
+#include "BlockAnvil.h"
#include "BlockBed.h"
#include "BlockBrewingStand.h"
#include "BlockButton.h"
#include "BlockCactus.h"
+#include "BlockCake.h"
#include "BlockCarpet.h"
#include "BlockCauldron.h"
#include "BlockChest.h"
@@ -85,12 +87,14 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
// Block handlers, alphabetically sorted:
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
+ case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType);
case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BROWN_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_CACTUS: return new cBlockCactusHandler (a_BlockType);
+ case E_BLOCK_CAKE: return new cBlockCakeHandler (a_BlockType);
case E_BLOCK_CARROTS: return new cBlockCropsHandler (a_BlockType);
case E_BLOCK_CARPET: return new cBlockCarpetHandler (a_BlockType);
case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType);
diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h
index 7b8f0b378..a6d3373c1 100644
--- a/src/Blocks/BlockLeaves.h
+++ b/src/Blocks/BlockLeaves.h
@@ -16,6 +16,7 @@
{ \
case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_LOG: return true; \
+ case E_BLOCK_NEW_LOG: return true; \
}
bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);
diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h
index 623cfda64..c30c1a401 100644
--- a/src/Blocks/BlockMushroom.h
+++ b/src/Blocks/BlockMushroom.h
@@ -39,6 +39,7 @@ public:
case E_BLOCK_CACTUS:
case E_BLOCK_ICE:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
case E_BLOCK_AIR:
{
return false;
diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h
index 708583e70..8041d9359 100644
--- a/src/Blocks/BlockVine.h
+++ b/src/Blocks/BlockVine.h
@@ -73,7 +73,7 @@ public:
/// Returns true if the specified block type is good for vines to attach to
static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
{
- return (a_BlockType == E_BLOCK_LEAVES) || cBlockInfo::IsSolid(a_BlockType);
+ return (a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType);
}
diff --git a/src/Blocks/BroadcastInterface.h b/src/Blocks/BroadcastInterface.h
index f6ccd580b..01966ffbd 100644
--- a/src/Blocks/BroadcastInterface.h
+++ b/src/Blocks/BroadcastInterface.h
@@ -5,6 +5,7 @@ class cBroadcastInterface
{
public:
- virtual void BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
- virtual void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
+ virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
+ virtual void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
+ virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
};
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index e59b00eff..580339d32 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -27,7 +27,13 @@ public:
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) = 0;
-
+
/** Sends the block on those coords to the player */
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player) = 0;
+
+ /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
+ virtual bool ForEachPlayer(cItemCallback<cPlayer> & a_Callback) = 0;
+
+ virtual void SetTimeOfDay(Int64 a_TimeOfDay) = 0;
+
};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0f8700692..0f0db9c80 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -57,6 +57,9 @@ if (NOT MSVC)
Entities/Player.h
Entities/ProjectileEntity.h
Entities/TNTEntity.h
+ Entities/ExpOrb.h
+ Entities/HangingEntity.h
+ Entities/ItemFrame.h
Generating/ChunkDesc.h
Group.h
Inventory.h
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 40964c654..62c1ec544 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1383,6 +1383,13 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
}
break;
}
+ case E_BLOCK_NEW_LEAVES:
+ {
+ if (itr->BlockType == E_BLOCK_NEW_LOG)
+ {
+ Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta);
+ }
+ }
}
} // for itr - a_Blocks[]
}
diff --git a/src/Defines.h b/src/Defines.h
index 3b7654265..38411c69d 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -530,16 +530,22 @@ enum eMessageType
// http://forum.mc-server.org/showthread.php?tid=1212
// MessageType...
- mtCustom, // Send raw data without any processing
- mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
- mtInformation, // Informational message (i.e. command usage)
- mtSuccess, // Something executed successfully
- mtWarning, // Something concerning (i.e. reload) is about to happen
- mtFatal, // Something catastrophic occured (i.e. plugin crash)
- mtDeath, // Denotes death of player
- mtPrivateMessage, // Player to player messaging identifier
- mtJoin, // A player has joined the server
- mtLeave, // A player has left the server
+ mtCustom, // Send raw data without any processing
+ mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
+ mtInformation, // Informational message (i.e. command usage)
+ mtSuccess, // Something executed successfully
+ mtWarning, // Something concerning (i.e. reload) is about to happen
+ mtFatal, // Something catastrophic occured (i.e. plugin crash)
+ mtDeath, // Denotes death of player
+ mtPrivateMessage, // Player to player messaging identifier
+ mtJoin, // A player has joined the server
+ mtLeave, // A player has left the server
+
+ // Common aliases:
+ mtFail = mtFailure,
+ mtError = mtFailure,
+ mtInfo = mtInformation,
+ mtPM = mtPrivateMessage,
};
diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp
index 3398f1c7b..3623c869a 100644
--- a/src/Entities/ExpOrb.cpp
+++ b/src/Entities/ExpOrb.cpp
@@ -5,20 +5,26 @@
#include "../ClientHandle.h"
-cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward) :
- cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98),
- m_Reward(a_Reward)
+cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
+ : cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98)
+ , m_Reward(a_Reward)
+ , m_Timer(0.f)
{
+ SetMaxHealth(5);
+ SetHealth(5);
}
-cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward) :
- cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
- m_Reward(a_Reward)
+cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward)
+ : cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
+ , m_Reward(a_Reward)
+ , m_Timer(0.f)
{
+ SetMaxHealth(5);
+ SetHealth(5);
}
@@ -52,7 +58,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
a_ClosestPlayer->DeltaExperience(m_Reward);
- m_World->BroadcastSoundEffect("random.orb", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_World->BroadcastSoundEffect("random.orb", (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}
@@ -64,4 +70,10 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
BroadcastMovementUpdate();
}
HandlePhysics(a_Dt, a_Chunk);
+
+ m_Timer += a_Dt;
+ if (m_Timer >= 1000 * 60 * 5) // 5 minutes
+ {
+ Destroy(true);
+ }
}
diff --git a/src/Entities/ExpOrb.h b/src/Entities/ExpOrb.h
index 47d86922c..c1150bd03 100644
--- a/src/Entities/ExpOrb.h
+++ b/src/Entities/ExpOrb.h
@@ -7,14 +7,17 @@
+// tolua_begin
class cExpOrb :
public cEntity
{
typedef cExpOrb super;
public:
+ // tolua_end
+
CLASS_PROTODEF(cExpOrb);
-
+
cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward);
cExpOrb(const Vector3d & a_Pos, int a_Reward);
@@ -22,9 +25,21 @@ public:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override;
- // cExpOrb functions
- int GetReward(void) const { return m_Reward; }
+ /** Returns the number of ticks that this entity has existed */
+ int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
+
+ /** Set the number of ticks that this entity has existed */
+ void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
+
+ /** Get the exp amount */
+ int GetReward(void) const { return m_Reward; } // tolua_export
+
+ /** Set the exp amount */
+ void SetReward(int a_Reward) { m_Reward = a_Reward; } // tolua_export
protected:
int m_Reward;
-} ; \ No newline at end of file
+
+ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
+ float m_Timer;
+} ; // tolua_export \ No newline at end of file
diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp
new file mode 100644
index 000000000..41ac86268
--- /dev/null
+++ b/src/Entities/HangingEntity.cpp
@@ -0,0 +1,53 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "HangingEntity.h"
+#include "ClientHandle.h"
+#include "Player.h"
+
+
+
+
+
+cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
+ : cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8)
+ , m_BlockFace(a_BlockFace)
+{
+ SetMaxHealth(1);
+ SetHealth(1);
+}
+
+
+
+
+
+void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ int Dir = 0;
+
+ // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
+ switch (m_BlockFace)
+ {
+ case BLOCK_FACE_ZP: break; // Initialised to zero
+ case BLOCK_FACE_ZM: Dir = 2; break;
+ case BLOCK_FACE_XM: Dir = 1; break;
+ case BLOCK_FACE_XP: Dir = 3; break;
+ default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
+ }
+
+ if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
+ {
+ SetYaw((Dir * 90) - 180);
+ }
+ else
+ {
+ SetYaw(Dir * 90);
+ }
+
+ a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
+ a_ClientHandle.SendEntityMetadata(*this);
+}
+
+
+
+
diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h
new file mode 100644
index 000000000..6498e4b5b
--- /dev/null
+++ b/src/Entities/HangingEntity.h
@@ -0,0 +1,49 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cHangingEntity :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+
+ CLASS_PROTODEF(cHangingEntity);
+
+ cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
+
+ /** Returns the orientation from the hanging entity */
+ eBlockFace GetDirection() const { return m_BlockFace; } // tolua_export
+
+ /** Set the orientation from the hanging entity */
+ void SetDirection(eBlockFace a_BlockFace) { m_BlockFace = a_BlockFace; } // tolua_export
+
+ /** Returns the X coord. */
+ int GetTileX() const { return POSX_TOINT; } // tolua_export
+
+ /** Returns the Y coord. */
+ int GetTileY() const { return POSY_TOINT; } // tolua_export
+
+ /** Returns the Z coord. */
+ int GetTileZ() const { return POSZ_TOINT; } // tolua_export
+
+private:
+
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
+
+ eBlockFace m_BlockFace;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp
index 8cfa5e18d..9dd909880 100644
--- a/src/Entities/ItemFrame.cpp
+++ b/src/Entities/ItemFrame.cpp
@@ -10,43 +10,10 @@
cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
- : cEntity(etItemFrame, a_X, a_Y, a_Z, 0.8, 0.8),
- m_BlockFace(a_BlockFace),
- m_Item(E_BLOCK_AIR),
- m_Rotation(0)
+ : cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z)
+ , m_Item(E_BLOCK_AIR)
+ , m_Rotation(0)
{
- SetMaxHealth(1);
- SetHealth(1);
-}
-
-
-
-
-
-void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle)
-{
- int Dir = 0;
-
- // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
- switch (m_BlockFace)
- {
- case BLOCK_FACE_ZP: break; // Initialised to zero
- case BLOCK_FACE_ZM: Dir = 2; break;
- case BLOCK_FACE_XM: Dir = 1; break;
- case BLOCK_FACE_XP: Dir = 3; break;
- default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
- }
-
- if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
- {
- SetYaw((Dir * 90) - 180);
- }
- else
- {
- SetYaw(Dir * 90);
- }
-
- a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
}
diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h
index 43915e3f9..6577e7d94 100644
--- a/src/Entities/ItemFrame.h
+++ b/src/Entities/ItemFrame.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Entity.h"
+#include "HangingEntity.h"
@@ -9,10 +9,10 @@
// tolua_begin
class cItemFrame :
- public cEntity
+ public cHangingEntity
{
// tolua_end
- typedef cEntity super;
+ typedef cHangingEntity super;
public:
@@ -20,18 +20,24 @@ public:
cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
- const cItem & GetItem(void) { return m_Item; }
- Byte GetRotation(void) const { return m_Rotation; }
+ /** Returns the item in the frame */
+ const cItem & GetItem(void) { return m_Item; } // tolua_export
+
+ /** Set the item in the frame */
+ void SetItem(cItem & a_Item) { m_Item = a_Item; }; // tolua_export
+
+ /** Returns the rotation from the item in the frame */
+ Byte GetRotation(void) const { return m_Rotation; } // tolua_export
+
+ /** Set the rotation from the item in the frame */
+ void SetRotation(Byte a_Rotation) { m_Rotation = a_Rotation; } // tolua_export
private:
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
virtual void KilledBy(cEntity * a_Killer) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
- eBlockFace m_BlockFace;
cItem m_Item;
Byte m_Rotation;
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index c5503c16a..7fc89b62b 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -82,7 +82,7 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_It
void cPickup::SpawnOn(cClientHandle & a_Client)
{
- a_Client.SendPickupSpawn(*this);
+ a_Client.SendPickupSpawn(*this);
}
diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h
index c273567d1..74b917bce 100644
--- a/src/Entities/Pickup.h
+++ b/src/Entities/Pickup.h
@@ -26,31 +26,34 @@ public:
CLASS_PROTODEF(cPickup);
cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f);
-
+
cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; }
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
-
+
bool CollectedBy(cPlayer * a_Dest); // tolua_export
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- /// Returns the number of ticks that this entity has existed
- int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
-
- /// Returns true if the pickup has already been collected
+
+ /** Returns the number of ticks that this entity has existed */
+ int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
+
+ /** Set the number of ticks that this entity has existed */
+ void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
+
+ /** Returns true if the pickup has already been collected */
bool IsCollected(void) const { return m_bCollected; } // tolua_export
- /// Returns true if created by player (i.e. vomiting), used for determining picking-up delay time
+ /** Returns true if created by player (i.e. vomiting), used for determining picking-up delay time */
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
-
+
private:
Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
Vector3d m_WaterSpeed;
- /// The number of ticks that the entity has existed / timer between collect and destroy; in msec
+ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer;
cItem m_Item;
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index f9404dfaf..c25053c21 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -270,6 +270,9 @@ public:
/// Returns true if the player is currently flying.
bool IsFlying(void) const { return m_IsFlying; }
+ /** Returns if a player is sleeping in a bed */
+ bool IsInBed(void) const { return m_bIsInBed; }
+
/// returns true if the player has thrown out a floater.
bool IsFishing(void) const { return m_IsFishing; }
@@ -278,6 +281,9 @@ public:
int GetFloaterID(void) const { return m_FloaterID; }
// tolua_end
+
+ /** Sets a player's in-bed state; we can't be sure plugins will keep this value updated, so no exporting */
+ void SetIsInBed(bool a_Flag) { m_bIsInBed = a_Flag; }
/// Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet
void StartEating(void);
@@ -371,8 +377,8 @@ protected:
GroupList m_ResolvedGroups;
GroupList m_Groups;
- std::string m_PlayerName;
- std::string m_LoadedWorldName;
+ AString m_PlayerName;
+ AString m_LoadedWorldName;
/// Xp Level stuff
enum
@@ -456,7 +462,7 @@ protected:
int m_FloaterID;
- cTeam* m_Team;
+ cTeam * m_Team;
@@ -479,6 +485,11 @@ protected:
/// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block)
void ApplyFoodExhaustionFromMovement();
+
+ /** Flag representing whether the player is currently in a bed
+ Set by a right click on unoccupied bed, unset by a time fast forward or teleport */
+ bool m_bIsInBed;
+
} ; // tolua_export
diff --git a/src/Items/ItemCake.h b/src/Items/ItemCake.h
new file mode 100644
index 000000000..48e23ed59
--- /dev/null
+++ b/src/Items/ItemCake.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemCakeHandler :
+ public cItemHandler
+{
+public:
+ cItemCakeHandler(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_CAKE;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 1d357fcf1..454fabdd7 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -13,6 +13,7 @@
#include "ItemBow.h"
#include "ItemBrewingStand.h"
#include "ItemBucket.h"
+#include "ItemCake.h"
#include "ItemCauldron.h"
#include "ItemCloth.h"
#include "ItemComparator.h"
@@ -94,6 +95,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
// Single item per handler, alphabetically sorted:
case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType);
+ case E_BLOCK_NEW_LEAVES: return new cItemLeavesHandler(a_ItemType);
case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
@@ -101,12 +103,14 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler();
case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
+ case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
case E_ITEM_EGG: return new cItemEggHandler();
case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler();
case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
+ case E_ITEM_FIRE_CHARGE: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler();
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
@@ -337,6 +341,7 @@ char cItemHandler::GetMaxStackSize(void)
case E_ITEM_BREWING_STAND: return 64;
case E_ITEM_BUCKET: return 16;
case E_ITEM_CARROT: return 64;
+ case E_ITEM_CAKE: return 1;
case E_ITEM_CAULDRON: return 64;
case E_ITEM_CLAY: return 64;
case E_ITEM_CLAY_BRICK: return 64;
diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h
index 74e987445..27e7dba35 100644
--- a/src/Items/ItemItemFrame.h
+++ b/src/Items/ItemItemFrame.h
@@ -34,7 +34,11 @@ public:
if (Block == E_BLOCK_AIR)
{
cItemFrame * ItemFrame = new cItemFrame(a_Dir, a_BlockX, a_BlockY, a_BlockZ);
- ItemFrame->Initialize(a_World);
+ if (!ItemFrame->Initialize(a_World))
+ {
+ delete ItemFrame;
+ return false;
+ }
if (!a_Player->IsGameModeCreative())
{
diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h
index 18873e911..2db6c829a 100644
--- a/src/Items/ItemLighter.h
+++ b/src/Items/ItemLighter.h
@@ -26,7 +26,26 @@ public:
return false;
}
- a_Player->UseEquippedItem();
+ if (!a_Player->IsGameModeCreative())
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_FLINT_AND_STEEL:
+ {
+ a_Player->UseEquippedItem();
+ break;
+ }
+ case E_ITEM_FIRE_CHARGE:
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unknown Lighter Item!");
+ }
+ }
+ }
switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))
{
@@ -49,6 +68,7 @@ public:
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
{
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
+ a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F);
break;
}
}
diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h
index b8f75f5ba..39d2776fa 100644
--- a/src/Items/ItemShears.h
+++ b/src/Items/ItemShears.h
@@ -28,10 +28,10 @@ public:
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (Block == E_BLOCK_LEAVES)
+ if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES))
{
cItems Drops;
- Drops.push_back(cItem(E_BLOCK_LEAVES, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
+ Drops.push_back(cItem(Block, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
@@ -49,6 +49,7 @@ public:
case E_BLOCK_COBWEB:
case E_BLOCK_VINES:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
{
return true;
}
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index 7704f6cf3..a0d0f5c54 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -169,7 +169,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(
- (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES)
+ (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
) &&
(a_RelY >= 62) &&
(m_Random.NextInt(3, a_Biome) != 0)
diff --git a/src/World.h b/src/World.h
index a772710ab..1950104a8 100644
--- a/src/World.h
+++ b/src/World.h
@@ -133,7 +133,7 @@ public:
m_WeatherInterval = a_WeatherInterval;
}
- void SetTimeOfDay(Int64 a_TimeOfDay)
+ virtual void SetTimeOfDay(Int64 a_TimeOfDay)
{
m_TimeOfDay = a_TimeOfDay;
m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
@@ -203,7 +203,7 @@ public:
void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
+ virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); // tolua_export
void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
@@ -216,7 +216,7 @@ public:
void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
- virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
+ virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
virtual cBroadcastInterface & GetBroadcastManager()
@@ -273,7 +273,7 @@ public:
void RemovePlayer( cPlayer* a_Player );
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
- bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+ virtual bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored */
bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 4cf3c62d7..acca96ba8 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -29,6 +29,9 @@
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
#include "../Entities/TNTEntity.h"
+#include "../Entities/ExpOrb.h"
+#include "../Entities/HangingEntity.h"
+#include "../Entities/ItemFrame.h"
#include "../Mobs/Monster.h"
#include "../Mobs/Bat.h"
@@ -526,8 +529,8 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
m_Writer.BeginCompound("");
AddBasicEntity(a_Pickup, "Item");
AddItem(a_Pickup->GetItem(), -1, "Item");
- m_Writer.AddShort("Health", a_Pickup->GetHealth());
- m_Writer.AddShort("Age", a_Pickup->GetAge());
+ m_Writer.AddShort("Health", (Int16)(unsigned char)a_Pickup->GetHealth());
+ m_Writer.AddShort("Age", (Int16)a_Pickup->GetAge());
m_Writer.EndCompound();
}
@@ -592,6 +595,25 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
+void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
+{
+ m_Writer.AddByte("Direction", (unsigned char)a_Hanging->GetDirection());
+ m_Writer.AddInt("TileX", a_Hanging->GetTileX());
+ m_Writer.AddInt("TileY", a_Hanging->GetTileY());
+ m_Writer.AddInt("TileZ", a_Hanging->GetTileZ());
+ switch (a_Hanging->GetDirection())
+ {
+ case 0: m_Writer.AddByte("Dir", (unsigned char)2); break;
+ case 1: m_Writer.AddByte("Dir", (unsigned char)1); break;
+ case 2: m_Writer.AddByte("Dir", (unsigned char)0); break;
+ case 3: m_Writer.AddByte("Dir", (unsigned char)3); break;
+ }
+}
+
+
+
+
+
void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
{
m_Writer.BeginCompound("");
@@ -604,6 +626,35 @@ void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
+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();
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_ItemFrame, "ItemFrame");
+ AddHangingEntity(a_ItemFrame);
+ AddItem(a_ItemFrame->GetItem(), -1, "Item");
+ m_Writer.AddByte("ItemRotation", (unsigned char)a_ItemFrame->GetRotation());
+ m_Writer.AddFloat("ItemDropChance", 1.0F);
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
@@ -684,8 +735,8 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break;
- case cEntity::etExpOrb: /* TODO */ break;
- case cEntity::etItemFrame: /* TODO */ break;
+ case cEntity::etExpOrb: AddExpOrbEntity ((cExpOrb *) a_Entity); break;
+ case cEntity::etItemFrame: AddItemFrameEntity ((cItemFrame *) a_Entity); break;
case cEntity::etPainting: /* TODO */ break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 3b486d2bc..c1134cd00 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -42,6 +42,9 @@ class cPickup;
class cItemGrid;
class cProjectileEntity;
class cTNTEntity;
+class cExpOrb;
+class cHangingEntity;
+class cItemFrame;
@@ -108,7 +111,10 @@ protected:
void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup);
void AddProjectileEntity (cProjectileEntity * a_Projectile);
+ void AddHangingEntity (cHangingEntity * a_Hanging);
void AddTNTEntity (cTNTEntity * a_TNT);
+ void AddExpOrbEntity (cExpOrb * a_ExpOrb);
+ void AddItemFrameEntity (cItemFrame * a_ItemFrame);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 070738164..7a2366755 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -37,6 +37,9 @@
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
#include "../Entities/TNTEntity.h"
+#include "../Entities/ExpOrb.h"
+#include "../Entities/HangingEntity.h"
+#include "../Entities/ItemFrame.h"
@@ -366,6 +369,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
{
case E_BLOCK_AIR:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
{
// nothing needed
break;
@@ -1098,6 +1102,18 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
+ {
+ LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
+ else if (strncmp(a_IDTag, "XPOrb", a_IDTagLength) == 0)
+ {
+ LoadExpOrbFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
+ else if (strncmp(a_IDTag, "ItemFrame", a_IDTagLength) == 0)
+ {
+ LoadItemFrameFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
else if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
{
LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@@ -1238,10 +1254,6 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPigZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
- else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
- {
- LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
- }
// TODO: other entities
}
@@ -1384,6 +1396,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
+ // Load item:
int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
{
@@ -1394,11 +1407,27 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
+
std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false
if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
{
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");
+ if (Age > 0)
+ {
+ Pickup->SetAge(a_NBT.GetShort(Age));
+ }
+
a_Entities.push_back(Pickup.release());
}
@@ -1406,6 +1435,148 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
+void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
+ if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ // Load Fuse Ticks:
+ int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
+ if (FuseTicks > 0)
+ {
+ TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
+ }
+
+ a_Entities.push_back(TNT.release());
+}
+
+
+
+
+
+void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0));
+ if (!LoadEntityBaseFromNBT(*ExpOrb.get(), a_NBT, a_TagIdx))
+ {
+ 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)
+ {
+ ExpOrb->SetAge(a_NBT.GetShort(Age));
+ }
+
+ // Load Reward (Value):
+ int Reward = a_NBT.FindChildByName(a_TagIdx, "Value");
+ if (Reward > 0)
+ {
+ ExpOrb->SetReward(a_NBT.GetShort(Reward));
+ }
+
+ a_Entities.push_back(ExpOrb.release());
+}
+
+
+
+
+
+void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ int Direction = a_NBT.FindChildByName(a_TagIdx, "Direction");
+ if (Direction > 0)
+ {
+ Direction = (int)a_NBT.GetByte(Direction);
+ if ((Direction < 0) || (Direction > 5))
+ {
+ a_Hanging.SetDirection(BLOCK_FACE_NORTH);
+ }
+ else
+ {
+ a_Hanging.SetDirection(static_cast<eBlockFace>(Direction));
+ }
+ }
+ else
+ {
+ Direction = a_NBT.FindChildByName(a_TagIdx, "Dir");
+ if (Direction > 0)
+ {
+ switch ((int)a_NBT.GetByte(Direction))
+ {
+ case 0: a_Hanging.SetDirection(BLOCK_FACE_NORTH); break;
+ case 1: a_Hanging.SetDirection(BLOCK_FACE_TOP); break;
+ case 2: a_Hanging.SetDirection(BLOCK_FACE_BOTTOM); break;
+ case 3: a_Hanging.SetDirection(BLOCK_FACE_SOUTH); break;
+ }
+ }
+ }
+
+ int TileX = a_NBT.FindChildByName(a_TagIdx, "TileX");
+ int TileY = a_NBT.FindChildByName(a_TagIdx, "TileY");
+ int TileZ = a_NBT.FindChildByName(a_TagIdx, "TileZ");
+ if ((TileX > 0) && (TileY > 0) && (TileZ > 0))
+ {
+ a_Hanging.SetPosition(
+ (double)a_NBT.GetInt(TileX),
+ (double)a_NBT.GetInt(TileY),
+ (double)a_NBT.GetInt(TileZ)
+ );
+ }
+}
+
+
+
+
+
+void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ // Load item:
+ int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
+ if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
+ {
+ return;
+ }
+ cItem Item;
+ if (!LoadItemFromNBT(Item, a_NBT, ItemTag))
+ {
+ return;
+ }
+
+ std::auto_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
+ if (!LoadEntityBaseFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+ ItemFrame->SetItem(Item);
+
+ LoadHangingFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx);
+
+ // Load Rotation:
+ int Rotation = a_NBT.FindChildByName(a_TagIdx, "ItemRotation");
+ if (Rotation > 0)
+ {
+ ItemFrame->SetRotation((Byte)a_NBT.GetByte(Rotation));
+ }
+
+ a_Entities.push_back(ItemFrame.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
@@ -2178,28 +2349,6 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT
-void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
-{
- std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
- if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
- {
- return;
- }
-
- // Load Fuse Ticks:
- int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
- if (FuseTicks > 0)
- {
- TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
- }
-
- a_Entities.push_back(TNT.release());
-}
-
-
-
-
-
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
{
double Pos[3];
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index fe93d16c3..50d0e555e 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -20,6 +20,7 @@
class cItemGrid;
class cProjectileEntity;
+class cHangingEntity;
@@ -149,6 +150,10 @@ protected:
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadExpOrbFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadHangingFromNBT (cHangingEntity & a_Hanging,const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadItemFrameFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
@@ -192,7 +197,6 @@ protected:
void LoadWolfFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
- void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
/// Loads entity common data from the NBT compound; returns true if successful
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);