diff options
-rw-r--r-- | src/BlockEntities/MobHeadEntity.cpp | 2 | ||||
-rw-r--r-- | src/BlockInfo.cpp | 2 | ||||
-rw-r--r-- | src/Blocks/BlockFire.h | 4 | ||||
-rw-r--r-- | src/Blocks/BlockHandler.cpp | 11 | ||||
-rw-r--r-- | src/Blocks/BlockHayBale.h | 29 | ||||
-rw-r--r-- | src/Blocks/BlockMobHead.h | 108 | ||||
-rw-r--r-- | src/Blocks/BlockPressurePlate.h | 38 | ||||
-rw-r--r-- | src/Blocks/BlockSlab.h | 1 | ||||
-rw-r--r-- | src/Blocks/WorldInterface.h | 9 | ||||
-rw-r--r-- | src/ChunkMap.h | 6 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 36 | ||||
-rw-r--r-- | src/Entities/ThrownSnowballEntity.cpp | 4 | ||||
-rw-r--r-- | src/Items/ItemThrowable.h | 11 | ||||
-rw-r--r-- | src/LightingThread.cpp | 92 | ||||
-rw-r--r-- | src/LightingThread.h | 11 | ||||
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator.cpp | 3 | ||||
-rw-r--r-- | src/World.h | 2 | ||||
-rw-r--r-- | src/WorldStorage/NBTChunkSerializer.cpp | 7 |
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: |