summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/BlockEntities/MobHeadEntity.cpp2
-rw-r--r--src/BlockInfo.cpp2
-rw-r--r--src/Blocks/BlockFire.h4
-rw-r--r--src/Blocks/BlockHandler.cpp11
-rw-r--r--src/Blocks/BlockHayBale.h29
-rw-r--r--src/Blocks/BlockMobHead.h108
-rw-r--r--src/Blocks/BlockPressurePlate.h38
-rw-r--r--src/Blocks/BlockSlab.h1
-rw-r--r--src/Blocks/WorldInterface.h9
-rw-r--r--src/ChunkMap.h6
-rw-r--r--src/ClientHandle.cpp36
-rw-r--r--src/Entities/ThrownSnowballEntity.cpp4
-rw-r--r--src/Items/ItemThrowable.h11
-rw-r--r--src/LightingThread.cpp92
-rw-r--r--src/LightingThread.h11
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp3
-rw-r--r--src/World.h2
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp7
18 files changed, 296 insertions, 80 deletions
diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp
index dc9c18d58..ce895eb6f 100644
--- a/src/BlockEntities/MobHeadEntity.cpp
+++ b/src/BlockEntities/MobHeadEntity.cpp
@@ -70,6 +70,8 @@ void cMobHeadEntity::SetOwner(const AString & a_Owner)
void cMobHeadEntity::SendTo(cClientHandle & a_Client)
{
+ cWorld * World = a_Client.GetPlayer()->GetWorld();
+ a_Client.SendBlockChange(m_PosX, m_PosY, m_PosZ, m_BlockType, World->GetBlockMeta(m_PosX, m_PosY, m_PosZ));
a_Client.SendUpdateBlockEntity(*this);
}
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index e8d9a7ec4..564b3fcca 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -341,6 +341,8 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_DANDELION ].m_IsSolid = false;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_END_PORTAL ].m_IsSolid = false;
+ ms_Info[E_BLOCK_FENCE ].m_IsSolid = false;
+ ms_Info[E_BLOCK_FENCE_GATE ].m_IsSolid = false;
ms_Info[E_BLOCK_FIRE ].m_IsSolid = false;
ms_Info[E_BLOCK_FLOWER ].m_IsSolid = false;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false;
diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h
index f9f32eb50..147e4b53e 100644
--- a/src/Blocks/BlockFire.h
+++ b/src/Blocks/BlockFire.h
@@ -36,8 +36,8 @@ public:
- Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
*/
- a_BlockY--; // Because we want the block below the fire
- FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface);
+ // a_BlockY - 1: Because we want the block below the fire
+ FindAndSetPortalFrame(a_BlockX, a_BlockY - 1, a_BlockZ, a_ChunkInterface, a_WorldInterface);
}
virtual void OnDigging(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 304e35e84..a7b89fcb7 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -38,6 +38,7 @@
#include "BlockGlass.h"
#include "BlockGlowstone.h"
#include "BlockGravel.h"
+#include "BlockHayBale.h"
#include "BlockMobHead.h"
#include "BlockHopper.h"
#include "BlockIce.h"
@@ -56,6 +57,7 @@
#include "BlockPlanks.h"
#include "BlockPortal.h"
#include "BlockPumpkin.h"
+#include "BlockPressurePlate.h"
#include "BlockQuartz.h"
#include "BlockRail.h"
#include "BlockRedstone.h"
@@ -130,10 +132,12 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_GLOWSTONE: return new cBlockGlowstoneHandler (a_BlockType);
case E_BLOCK_GOLD_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_GLASS: return new cBlockGlassHandler (a_BlockType);
+ case E_BLOCK_GLASS_PANE: return new cBlockGlassHandler (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_HAY_BALE: return new cBlockHayBaleHandler (a_BlockType);
case E_BLOCK_HEAD: return new cBlockMobHeadHandler (a_BlockType);
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: return new cBlockPressurePlateHandler(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);
@@ -149,6 +153,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_LEAVES: return new cBlockLeavesHandler (a_BlockType);
case E_BLOCK_LILY_PAD: return new cBlockLilypadHandler (a_BlockType);
case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (a_BlockType);
+ case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return new cBlockPressurePlateHandler(a_BlockType);
case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (a_BlockType);
@@ -186,12 +191,15 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_SIGN_POST: return new cBlockSignHandler (a_BlockType);
case E_BLOCK_SNOW: return new cBlockSnowHandler (a_BlockType);
case E_BLOCK_SPRUCE_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
+ case E_BLOCK_STAINED_GLASS: return new cBlockGlassHandler (a_BlockType);
+ case E_BLOCK_STAINED_GLASS_PANE: return new cBlockGlassHandler (a_BlockType);
case E_BLOCK_STATIONARY_LAVA: return new cBlockLavaHandler (a_BlockType);
case E_BLOCK_STATIONARY_WATER: return new cBlockFluidHandler (a_BlockType);
case E_BLOCK_STICKY_PISTON: return new cBlockPistonHandler (a_BlockType);
case E_BLOCK_STONE: return new cBlockStoneHandler (a_BlockType);
case E_BLOCK_STONE_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_STONE_BUTTON: return new cBlockButtonHandler (a_BlockType);
+ case E_BLOCK_STONE_PRESSURE_PLATE: return new cBlockPressurePlateHandler (a_BlockType);
case E_BLOCK_STONE_SLAB: return new cBlockSlabHandler (a_BlockType);
case E_BLOCK_SUGARCANE: return new cBlockSugarcaneHandler (a_BlockType);
case E_BLOCK_TALL_GRASS: return new cBlockTallGrassHandler (a_BlockType);
@@ -203,6 +211,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
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);
+ case E_BLOCK_WOODEN_PRESSURE_PLATE: return new cBlockPressurePlateHandler (a_BlockType);
case E_BLOCK_WOODEN_SLAB: return new cBlockSlabHandler (a_BlockType);
case E_BLOCK_WOODEN_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_WOOL: return new cBlockClothHandler (a_BlockType);
diff --git a/src/Blocks/BlockHayBale.h b/src/Blocks/BlockHayBale.h
new file mode 100644
index 000000000..5b646e264
--- /dev/null
+++ b/src/Blocks/BlockHayBale.h
@@ -0,0 +1,29 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "BlockSideways.h"
+
+
+
+
+
+class cBlockHayBaleHandler :
+ public cBlockSidewaysHandler
+{
+public:
+ cBlockHayBaleHandler(BLOCKTYPE a_BlockType)
+ : cBlockSidewaysHandler(a_BlockType)
+ {
+ }
+
+
+ virtual const char * GetStepSound(void) override
+ {
+ return "step.grass";
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index 9855574ad..301386568 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -19,24 +19,69 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
- a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0));
+ // The drop spawn is in OnDestroyed method
}
+
+ virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ if (a_Player->IsGameModeCreative())
+ {
+ // No drops in creative mode
+ return;
+ }
+
+ class cCallback : public cBlockEntityCallback
+ {
+ virtual bool Item(cBlockEntity * a_BlockEntity)
+ {
+ if (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)
+ {
+ return false;
+ }
+ cMobHeadEntity * MobHeadEntity = static_cast<cMobHeadEntity*>(a_BlockEntity);
+
+ cItems Pickups;
+ Pickups.Add(E_ITEM_HEAD, 1, (short) MobHeadEntity->GetType());
+ MTRand r1;
+
+ // Mid-block position first
+ double MicroX, MicroY, MicroZ;
+ MicroX = MobHeadEntity->GetPosX() + 0.5;
+ MicroY = MobHeadEntity->GetPosY() + 0.5;
+ MicroZ = MobHeadEntity->GetPosZ() + 0.5;
+
+ // Add random offset second
+ MicroX += r1.rand(1) - 0.5;
+ MicroZ += r1.rand(1) - 0.5;
- bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
+ MobHeadEntity->GetWorld()->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ);
+ return false;
+ }
+ } Callback;
+
+ a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
+ }
+
+ bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
if (a_BlockY < 2)
{
return false;
}
- class cCallback : public cMobHeadCallback
+ class cCallback : public cBlockEntityCallback
{
bool m_IsWither;
- virtual bool Item (cMobHeadEntity * a_MobHeadEntity)
+ virtual bool Item(cBlockEntity * a_BlockEntity)
{
- m_IsWither = (a_MobHeadEntity->GetType() == SKULL_TYPE_WITHER);
+ if (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)
+ {
+ return false;
+ }
+ cMobHeadEntity * MobHeadEntity = static_cast<cMobHeadEntity*>(a_BlockEntity);
+ m_IsWither = (MobHeadEntity->GetType() == SKULL_TYPE_WITHER);
return false;
}
@@ -70,7 +115,7 @@ public:
} PlayerCallback(Vector3f((float)a_BlockX, (float)a_BlockY, (float)a_BlockZ));
- a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
+ a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
if (!CallbackA.IsWither())
{
@@ -87,8 +132,8 @@ public:
return false;
}
- a_World->DoWithMobHeadAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA);
- a_World->DoWithMobHeadAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB);
+ a_WorldInterface.DoWithBlockEntityAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA);
+ a_WorldInterface.DoWithBlockEntityAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB);
BLOCKTYPE Block1 = a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ);
BLOCKTYPE Block2 = a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ);
@@ -101,15 +146,15 @@ public:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
- a_World->SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_World->SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
// Spawn the wither:
- a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+ a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
// Award Achievement
- a_World->ForEachPlayer(PlayerCallback);
+ a_WorldInterface.ForEachPlayer(PlayerCallback);
return true;
}
@@ -117,8 +162,8 @@ public:
CallbackA.Reset();
CallbackB.Reset();
- a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA);
- a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB);
+ a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA);
+ a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB);
Block1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1);
Block2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1);
@@ -131,15 +176,15 @@ public:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
// Spawn the wither:
- a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+ a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
// Award Achievement
- a_World->ForEachPlayer(PlayerCallback);
+ a_WorldInterface.ForEachPlayer(PlayerCallback);
return true;
}
@@ -154,23 +199,29 @@ public:
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
- class cCallback : public cMobHeadCallback
+ class cCallback : public cBlockEntityCallback
{
cPlayer * m_Player;
NIBBLETYPE m_OldBlockMeta;
NIBBLETYPE m_NewBlockMeta;
- virtual bool Item (cMobHeadEntity * a_MobHeadEntity)
+ virtual bool Item(cBlockEntity * a_BlockEntity)
{
+ if (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)
+ {
+ return false;
+ }
+ cMobHeadEntity * MobHeadEntity = static_cast<cMobHeadEntity*>(a_BlockEntity);
+
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));
- a_MobHeadEntity->GetWorld()->BroadcastBlockEntity(a_MobHeadEntity->GetPosX(), a_MobHeadEntity->GetPosY(), a_MobHeadEntity->GetPosZ(), m_Player->GetClientHandle());
+
+ MobHeadEntity->SetType(static_cast<eMobHeadType>(m_OldBlockMeta));
+ MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation));
+ MobHeadEntity->GetWorld()->BroadcastBlockEntity(MobHeadEntity->GetPosX(), MobHeadEntity->GetPosY(), MobHeadEntity->GetPosZ());
return false;
}
@@ -184,8 +235,7 @@ public:
cCallback Callback(a_Player, a_BlockMeta, static_cast<NIBBLETYPE>(a_BlockFace));
a_BlockMeta = (NIBBLETYPE)a_BlockFace;
- cWorld * World = (cWorld *) &a_WorldInterface;
- World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
+ a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
if (a_BlockMeta == SKULL_TYPE_WITHER)
@@ -200,7 +250,7 @@ public:
};
for (size_t i = 0; i < ARRAYCOUNT(Coords); ++i)
{
- if (TrySpawnWither(a_ChunkInterface, World, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z))
+ if (TrySpawnWither(a_ChunkInterface, a_WorldInterface, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z))
{
break;
}
diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h
new file mode 100644
index 000000000..adec36eb6
--- /dev/null
+++ b/src/Blocks/BlockPressurePlate.h
@@ -0,0 +1,38 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+class cBlockPressurePlateHandler :
+ public cBlockHandler
+{
+public:
+ cBlockPressurePlateHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ // Reset meta to 0
+ a_Pickups.push_back(cItem(m_BlockType, 1, 0));
+ }
+
+ virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
+ {
+ if (a_RelY <= 0)
+ {
+ return false;
+ }
+
+ BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
+ return ((BlockBelow == E_BLOCK_FENCE_GATE) || (BlockBelow == E_BLOCK_FENCE) || cBlockInfo::IsSolid(BlockBelow));
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h
index 80841b094..f3f2366fd 100644
--- a/src/Blocks/BlockSlab.h
+++ b/src/Blocks/BlockSlab.h
@@ -80,6 +80,7 @@ public:
if (IsAnySlabType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)))
{
a_BlockType = GetDoubleSlabType(m_BlockType);
+ a_BlockMeta = a_BlockMeta & 0x7;
}
return true;
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index bfbb053d9..650a216c0 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -6,6 +6,12 @@
class cItems;
+typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
+
+
+
+
+
class cWorldInterface
{
public:
@@ -29,6 +35,9 @@ 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;
+ /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
+ virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) = 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;
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 5aad0dd2a..3ee0bab3c 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -35,8 +35,8 @@ class cBlockArea;
class cMobCensus;
class cMobSpawner;
-typedef std::list<cClientHandle *> cClientHandleList;
-typedef cChunk * cChunkPtr;
+typedef std::list<cClientHandle *> cClientHandleList;
+typedef cChunk * cChunkPtr;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
@@ -450,7 +450,7 @@ private:
/** The cChunkStay descendants that are currently enabled in this chunkmap */
cChunkStays m_ChunkStays;
- std::auto_ptr<cAllocationPool<cChunkData::sChunkSection>> m_Pool;
+ std::auto_ptr<cAllocationPool<cChunkData::sChunkSection> > m_Pool;
cChunkPtr GetChunk (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid
cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index e4bb9d8e9..ade7e20ac 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -953,6 +953,26 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
m_LastDigBlockY = a_BlockY;
m_LastDigBlockZ = a_BlockZ;
+ // Check for clickthrough-blocks:
+ /* When the user breaks a fire block, the client send the wrong block location.
+ We must find the right block with the face direction. */
+ if (a_BlockFace != BLOCK_FACE_NONE)
+ {
+ int pX = a_BlockX;
+ int pY = a_BlockY;
+ int pZ = a_BlockZ;
+
+ AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false)
+ cBlockHandler * Handler = cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(pX, pY, pZ));
+
+ if (Handler->IsClickedThrough())
+ {
+ cChunkInterface ChunkInterface(m_Player->GetWorld()->GetChunkMap());
+ Handler->OnDigging(ChunkInterface, *m_Player->GetWorld(), m_Player, pX, pY, pZ);
+ return;
+ }
+ }
+
if (
(m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately
cBlockInfo::IsOneHitDig(a_OldBlock) // One-hit blocks get destroyed immediately, too
@@ -979,22 +999,6 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
ItemHandler->OnDiggingBlock(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-
- // Check for clickthrough-blocks:
- if (a_BlockFace != BLOCK_FACE_NONE)
- {
- int pX = a_BlockX;
- int pY = a_BlockY;
- int pZ = a_BlockZ;
-
- AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false)
- Handler = cBlockInfo::GetHandler(World->GetBlock(pX, pY, pZ));
-
- if (Handler->IsClickedThrough())
- {
- Handler->OnDigging(ChunkInterface, *World, m_Player, pX, pY, pZ);
- }
- }
}
diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp
index 427f630f7..cefc3433c 100644
--- a/src/Entities/ThrownSnowballEntity.cpp
+++ b/src/Entities/ThrownSnowballEntity.cpp
@@ -36,10 +36,6 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d &
{
TotalDamage = 3;
}
- else if (MobType == cMonster::mtEnderDragon)
- {
- TotalDamage = 1;
- }
}
// TODO: If entity is Ender Crystal, destroy it
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
index 35c2b8731..25935a1bc 100644
--- a/src/Items/ItemThrowable.h
+++ b/src/Items/ItemThrowable.h
@@ -31,6 +31,17 @@ public:
Vector3d Pos = a_Player->GetThrowStartPos();
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
+ // Play sound
+ cFastRandom Random;
+ a_World->BroadcastSoundEffect(
+ "random.bow",
+ (int)std::floor(a_Player->GetPosX() * 8.0),
+ (int)std::floor((a_Player->GetPosY() - a_Player->GetHeight()) * 8.0),
+ (int)std::floor(a_Player->GetPosZ() * 8.0),
+ 0.5F,
+ 0.4F / (Random.NextFloat(1.0F) * 0.4F + 0.8F)
+ );
+
if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed) < 0)
{
return false;
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp
index dc19bf500..33bc08467 100644
--- a/src/LightingThread.cpp
+++ b/src/LightingThread.cpp
@@ -23,7 +23,8 @@ class cReader :
BLOCKTYPE * OutputRows = m_BlockTypes;
int InputIdx = 0;
int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
- for (int y = 0; y < cChunkDef::Height; y++)
+ int MaxHeight = std::min(+cChunkDef::Height, m_MaxHeight + 16); // Need 16 blocks above the highest
+ for (int y = 0; y < MaxHeight; y++)
{
for (int z = 0; z < cChunkDef::Width; z++)
{
@@ -40,6 +41,7 @@ class cReader :
virtual void HeightMap(const cChunkDef::HeightMap * a_Heightmap) override
{
+ // Copy the entire heightmap, distribute it into the 3x3 chunk blob:
typedef struct {HEIGHTTYPE m_Row[16]; } ROW;
ROW * InputRows = (ROW *)a_Heightmap;
ROW * OutputRows = (ROW *)m_HeightMap;
@@ -50,13 +52,32 @@ class cReader :
OutputRows[OutputIdx] = InputRows[InputIdx++];
OutputIdx += 3;
} // for z
+
+ // Find the highest block in the entire chunk, use it as a base for m_MaxHeight:
+ HEIGHTTYPE MaxHeight = m_MaxHeight;
+ for (size_t i = 0; i < ARRAYCOUNT(*a_Heightmap); i++)
+ {
+ if ((*a_Heightmap)[i] > MaxHeight)
+ {
+ MaxHeight = (*a_Heightmap)[i];
+ }
+ }
+ m_MaxHeight = MaxHeight;
}
public:
int m_ReadingChunkX; // 0, 1 or 2; x-offset of the chunk we're reading from the BlockTypes start
int m_ReadingChunkZ; // 0, 1 or 2; z-offset of the chunk we're reading from the BlockTypes start
+ HEIGHTTYPE m_MaxHeight; // Maximum value in this chunk's heightmap
BLOCKTYPE * m_BlockTypes; // 3x3 chunks of block types, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
HEIGHTTYPE * m_HeightMap; // 3x3 chunks of height map, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
+
+ cReader(BLOCKTYPE * a_BlockTypes, HEIGHTTYPE * a_HeightMap) :
+ m_MaxHeight(0),
+ m_BlockTypes(a_BlockTypes),
+ m_HeightMap(a_HeightMap)
+ {
+ }
} ;
@@ -224,7 +245,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
// DEBUG: Save chunk data with highlighted seeds for visual inspection:
cFile f4;
if (
- f4.Open(Printf("Chunk_%d_%d_seeds.grab", a_Item.x, a_Item.z), cFile::fmWrite)
+ f4.Open(Printf("Chunk_%d_%d_seeds.grab", a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite)
)
{
for (int z = 0; z < cChunkDef::Width * 3; z++)
@@ -243,6 +264,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
f4.Write(Seeds, cChunkDef::Width * 3);
}
}
+ f4.Close();
}
//*/
@@ -252,9 +274,9 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
// DEBUG: Save XY slices of the chunk data and lighting for visual inspection:
cFile f1, f2, f3;
if (
- f1.Open(Printf("Chunk_%d_%d_data.grab", a_Item.x, a_Item.z), cFile::fmWrite) &&
- f2.Open(Printf("Chunk_%d_%d_sky.grab", a_Item.x, a_Item.z), cFile::fmWrite) &&
- f3.Open(Printf("Chunk_%d_%d_glow.grab", a_Item.x, a_Item.z), cFile::fmWrite)
+ f1.Open(Printf("Chunk_%d_%d_data.grab", a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite) &&
+ f2.Open(Printf("Chunk_%d_%d_sky.grab", a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite) &&
+ f3.Open(Printf("Chunk_%d_%d_glow.grab", a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite)
)
{
for (int z = 0; z < cChunkDef::Width * 3; z++)
@@ -273,6 +295,9 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
f3.Write(BlockLight, cChunkDef::Width * 3);
}
}
+ f1.Close();
+ f2.Close();
+ f3.Close();
}
//*/
@@ -293,11 +318,9 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
-bool cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ)
+void cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ)
{
- cReader Reader;
- Reader.m_BlockTypes = m_BlockTypes;
- Reader.m_HeightMap = m_HeightMap;
+ cReader Reader(m_BlockTypes, m_HeightMap);
for (int z = 0; z < 3; z++)
{
@@ -305,16 +328,13 @@ bool cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ)
for (int x = 0; x < 3; x++)
{
Reader.m_ReadingChunkX = x;
- if (!m_World->GetChunkData(a_ChunkX + x - 1, a_ChunkZ + z - 1, Reader))
- {
- return false;
- }
+ VERIFY(m_World->GetChunkData(a_ChunkX + x - 1, a_ChunkZ + z - 1, Reader));
} // for z
} // for x
memset(m_BlockLight, 0, sizeof(m_BlockLight));
memset(m_SkyLight, 0, sizeof(m_SkyLight));
- return true;
+ m_MaxHeight = Reader.m_MaxHeight;
}
@@ -405,6 +425,50 @@ void cLightingThread::PrepareBlockLight(void)
+void cLightingThread::PrepareBlockLight2(void)
+{
+ // Clear seeds:
+ memset(m_IsSeed1, 0, sizeof(m_IsSeed1));
+ memset(m_IsSeed2, 0, sizeof(m_IsSeed2));
+ m_NumSeeds = 0;
+
+ // Add each emissive block into the seeds:
+ for (int y = 0; y < m_MaxHeight; y++)
+ {
+ int BaseY = y * BlocksPerYLayer; // Partial offset into m_BlockTypes for the Y coord
+ for (int z = 1; z < cChunkDef::Width * 3 - 1; z++)
+ {
+ int HBaseZ = z * cChunkDef::Width * 3; // Partial offset into m_Heightmap for the Z coord
+ int BaseZ = BaseY + HBaseZ; // Partial offset into m_BlockTypes for the Y and Z coords
+ for (int x = 1; x < cChunkDef::Width * 3 - 1; x++)
+ {
+ int idx = BaseZ + x;
+ if (y > m_HeightMap[HBaseZ + x])
+ {
+ // We're above the heightmap, ignore the block
+ continue;
+ }
+ if (cBlockInfo::GetLightValue(m_BlockTypes[idx]) == 0)
+ {
+ // Not a light-emissive block
+ continue;
+ }
+
+ // Add current block as a seed:
+ m_IsSeed1[idx] = true;
+ m_SeedIdx1[m_NumSeeds++] = idx;
+
+ // Light it up:
+ m_BlockLight[idx] = cBlockInfo::GetLightValue(m_BlockTypes[idx]);
+ }
+ }
+ }
+}
+
+
+
+
+
void cLightingThread::CalcLight(NIBBLETYPE * a_Light)
{
int NumSeeds2 = 0;
diff --git a/src/LightingThread.h b/src/LightingThread.h
index 770ae809f..a484fcbed 100644
--- a/src/LightingThread.h
+++ b/src/LightingThread.h
@@ -108,6 +108,9 @@ protected:
cEvent m_evtItemAdded; // Set when queue is appended, or to stop the thread
cEvent m_evtQueueEmpty; // Set when the queue gets empty
+ /** The highest block in the current 3x3 chunk data */
+ HEIGHTTYPE m_MaxHeight;
+
// Buffers for the 3x3 chunk data
// These buffers alone are 1.7 MiB in size, therefore they cannot be located on the stack safely - some architectures may have only 1 MiB for stack, or even less
@@ -136,8 +139,8 @@ protected:
/** Lights the entire chunk. If neighbor chunks don't exist, touches them and re-queues the chunk */
void LightChunk(cLightingChunkStay & a_Item);
- /** Prepares m_BlockTypes and m_HeightMap data; returns false if any of the chunks fail. Zeroes out the light arrays */
- bool ReadChunks(int a_ChunkX, int a_ChunkZ);
+ /** Prepares m_BlockTypes and m_HeightMap data; zeroes out the light arrays */
+ void ReadChunks(int a_ChunkX, int a_ChunkZ);
/** Uses m_HeightMap to initialize the m_SkyLight[] data; fills in seeds for the skylight */
void PrepareSkyLight(void);
@@ -145,6 +148,10 @@ protected:
/** Uses m_BlockTypes to initialize the m_BlockLight[] data; fills in seeds for the blocklight */
void PrepareBlockLight(void);
+ /** Same as PrepareBlockLight(), but uses a different traversal scheme; possibly better perf cache-wise.
+ To be compared in perf benchmarks. */
+ void PrepareBlockLight2(void);
+
/** Calculates light in the light array specified, using stored seeds */
void CalcLight(NIBBLETYPE * a_Light);
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index 1e7ff543d..183c527ca 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -514,8 +514,7 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBl
{
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- cChunkInterface ChunkInterface(m_World.GetChunkMap());
- NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ NIBBLETYPE MetaData = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
diff --git a/src/World.h b/src/World.h
index 3e63e2b8c..f638b4b22 100644
--- a/src/World.h
+++ b/src/World.h
@@ -532,7 +532,7 @@ public:
virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) override; // tolua_export
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
- bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+ virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) override; // Exported in ManualBindings.cpp
/** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index a3b0d57be..8294d4a00 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -608,17 +608,12 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
case cProjectileEntity::pkGhastFireball:
{
m_Writer.AddInt("ExplosionPower", 1);
- // fall-through:
+ break;
}
case cProjectileEntity::pkFireCharge:
case cProjectileEntity::pkWitherSkull:
case cProjectileEntity::pkEnderPearl:
{
- m_Writer.BeginList("Motion", TAG_Double);
- m_Writer.AddDouble("", a_Projectile->GetSpeedX());
- m_Writer.AddDouble("", a_Projectile->GetSpeedY());
- m_Writer.AddDouble("", a_Projectile->GetSpeedZ());
- m_Writer.EndList();
break;
}
default: