summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/Chunk.h3
-rw-r--r--source/Entity.cpp4
-rw-r--r--source/FallingBlock.cpp45
-rw-r--r--source/FallingBlock.h15
-rw-r--r--source/Simulator/SandSimulator.cpp235
-rw-r--r--source/Simulator/SandSimulator.h58
-rw-r--r--source/World.cpp10
-rw-r--r--source/World.h2
8 files changed, 283 insertions, 89 deletions
diff --git a/source/Chunk.h b/source/Chunk.h
index 853f1e61a..4d88d1019 100644
--- a/source/Chunk.h
+++ b/source/Chunk.h
@@ -5,6 +5,7 @@
#include "ChunkDef.h"
#include "Simulator/FireSimulator.h"
+#include "Simulator/SandSimulator.h"
@@ -271,6 +272,7 @@ public:
cFireSimulatorChunkData & GetFireSimulatorData (void) { return m_FireSimulatorData; }
cFluidSimulatorData * GetWaterSimulatorData(void) { return m_WaterSimulatorData; }
cFluidSimulatorData * GetLavaSimulatorData (void) { return m_LavaSimulatorData; }
+ cSandSimulatorChunkData & GetSandSimulatorData (void) { return m_SandSimulatorData; }
private:
@@ -319,6 +321,7 @@ private:
cFireSimulatorChunkData m_FireSimulatorData;
cFluidSimulatorData * m_WaterSimulatorData;
cFluidSimulatorData * m_LavaSimulatorData;
+ cSandSimulatorChunkData m_SandSimulatorData;
void RemoveBlockEntity(cBlockEntity * a_BlockEntity);
diff --git a/source/Entity.cpp b/source/Entity.cpp
index c031c97af..bbca17fce 100644
--- a/source/Entity.cpp
+++ b/source/Entity.cpp
@@ -50,9 +50,9 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z)
cEntity::~cEntity()
{
- LOGD("Deleting entity %d at pos {%.2f, %.2f} ~ [%d, %d]; ptr %p",
+ LOGD("Deleting entity %d at pos {%.2f, %.2f, %.2f} ~ [%d, %d]; ptr %p",
m_UniqueID,
- m_Pos.x, m_Pos.z,
+ m_Pos.x, m_Pos.y, m_Pos.z,
(int)(m_Pos.x / cChunkDef::Width), (int)(m_Pos.z / cChunkDef::Width),
this
);
diff --git a/source/FallingBlock.cpp b/source/FallingBlock.cpp
index 8f0320d9b..12362009d 100644
--- a/source/FallingBlock.cpp
+++ b/source/FallingBlock.cpp
@@ -3,15 +3,17 @@
#include "FallingBlock.h"
#include "World.h"
#include "ClientHandle.h"
+#include "Simulator/SandSimulator.h"
-cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType)
- : super(etFallingBlock, a_BlockPosition.x + 0.5f, a_BlockPosition.y + 0.5f, a_BlockPosition.z + 0.5f)
- , m_BlockType(a_BlockType)
- , m_OriginalPosition(a_BlockPosition)
+cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
+ super(etFallingBlock, a_BlockPosition.x + 0.5f, a_BlockPosition.y + 0.5f, a_BlockPosition.z + 0.5f),
+ m_BlockType(a_BlockType),
+ m_BlockMeta(a_BlockMeta),
+ m_OriginalPosition(a_BlockPosition)
{
}
@@ -21,7 +23,7 @@ cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_Block
void cFallingBlock::Initialize(cWorld * a_World)
{
- super::Initialize( a_World );
+ super::Initialize(a_World);
a_World->BroadcastSpawn(*this);
}
@@ -44,13 +46,34 @@ void cFallingBlock::Tick(float a_Dt, MTRand & a_TickRandom)
m_Speed.y -= MilliDt * 9.8f;
m_Pos.y += m_Speed.y * MilliDt;
- // GetWorld()->BroadcastTeleportEntity(*this); // Testing position
-
- Vector3i BlockPos( m_OriginalPosition.x, (int)(m_Pos.y - 0.5), m_OriginalPosition.z);
- if (!IsPassable(GetWorld()->GetBlock(BlockPos)))
+ // GetWorld()->BroadcastTeleportEntity(*this); // Test position
+
+ int BlockX = (int)m_OriginalPosition.x;
+ int BlockY = (int)(m_Pos.y - 0.5);
+ int BlockZ = (int)m_OriginalPosition.z;
+
+ if (BlockY < 0)
+ {
+ // Fallen out of this world, just continue falling until out of sight, then destroy:
+ if (BlockY < 100)
+ {
+ Destroy();
+ }
+ return;
+ }
+
+ if (BlockY < cChunkDef::Height - 1)
{
- Destroy();
- GetWorld()->SetBlock(BlockPos.x, BlockPos.y + 1, BlockPos.z, m_BlockType, 0);
+ BLOCKTYPE BlockBelow = GetWorld()->GetBlock(BlockX, BlockY, BlockZ);
+ if (
+ cSandSimulator::DoesBreakFallingThrough(BlockBelow) || // Fallen onto a block that breaks this into pickups (e. g. half-slab)
+ !cSandSimulator::CanContinueFallThrough(BlockBelow) // Fallen onto a solid block
+ )
+ {
+ cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta);
+ Destroy();
+ return;
+ }
}
}
diff --git a/source/FallingBlock.h b/source/FallingBlock.h
index abc3f8d9b..37fb4c4cc 100644
--- a/source/FallingBlock.h
+++ b/source/FallingBlock.h
@@ -23,9 +23,10 @@ class cFallingBlock :
public:
CLASS_PROTODEF(cFallingBlock);
- cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType);
+ cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
- BLOCKTYPE GetBlockType(void) const { return m_BlockType; }
+ BLOCKTYPE GetBlockType(void) const { return m_BlockType; }
+ NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; }
// cEntity overrides:
virtual void Initialize(cWorld * a_World) override;
@@ -33,13 +34,9 @@ public:
virtual void Tick(float a_Dt, MTRand & a_TickRandom) override;
private:
- BLOCKTYPE m_BlockType;
- Vector3i m_OriginalPosition;
-
- static bool IsPassable(BLOCKTYPE a_BlockType)
- {
- return ((a_BlockType == E_BLOCK_AIR) || IsBlockLiquid(a_BlockType));
- }
+ BLOCKTYPE m_BlockType;
+ NIBBLETYPE m_BlockMeta;
+ Vector3i m_OriginalPosition;
} ;
diff --git a/source/Simulator/SandSimulator.cpp b/source/Simulator/SandSimulator.cpp
index 04bcc498c..27e137354 100644
--- a/source/Simulator/SandSimulator.cpp
+++ b/source/Simulator/SandSimulator.cpp
@@ -12,102 +12,243 @@
-cSandSimulator::cSandSimulator(cWorld & a_World)
- : cSimulator(a_World)
- , m_Blocks(new BlockList)
- , m_Buffer(new BlockList)
+cSandSimulator::cSandSimulator(cWorld & a_World, cIniFile & a_IniFile) :
+ cSimulator(a_World),
+ m_TotalBlocks(0)
{
+ m_IsInstantFall = a_IniFile.GetValueSetB("Physics", "SandInstantFall", false);
+}
+
+
+
+
+
+void cSandSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
+{
+ cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
+ if (ChunkData.empty())
+ {
+ return;
+ }
+ int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
+ int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
+ for (cSandSimulatorChunkData::const_iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr)
+ {
+ BLOCKTYPE BlockType = a_Chunk->GetBlock(itr->x, itr->y, itr->z);
+ if (!IsAllowedBlock(BlockType) || (itr->y <= 0))
+ {
+ continue;
+ }
+
+ BLOCKTYPE BlockBelow = (itr->y > 0) ? a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z) : E_BLOCK_AIR;
+ if (CanStartFallingThrough(BlockBelow))
+ {
+ if (m_IsInstantFall)
+ {
+ DoInstantFall(a_Chunk, itr->x, itr->y, itr->z);
+ continue;
+ }
+ Vector3i Pos;
+ Pos.x = itr->x + BaseX;
+ Pos.y = itr->y;
+ Pos.z = itr->z + BaseZ;
+ cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z));
+ FallingBlock->Initialize(&m_World);
+ a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0);
+ }
+ }
+ m_TotalBlocks -= ChunkData.size();
+ ChunkData.clear();
}
-cSandSimulator::~cSandSimulator()
+bool cSandSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
{
- delete m_Buffer;
- delete m_Blocks;
+ switch (a_BlockType)
+ {
+ case E_BLOCK_SAND:
+ case E_BLOCK_GRAVEL:
+ case E_BLOCK_ANVIL:
+ {
+ return true;
+ }
+ }
+ return false;
}
-void cSandSimulator::Simulate(float a_Dt)
+void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
{
- m_Buffer->clear();
- std::swap( m_Blocks, m_Buffer );
+ if (a_Chunk == NULL)
+ {
+ return;
+ }
+ int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
+ int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
+ if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ)))
+ {
+ return;
+ }
- for( BlockList::iterator itr = m_Buffer->begin(); itr != m_Buffer->end(); ++itr )
+ // Check for duplicates:
+ cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
+ for (cSandSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
{
- Vector3i Pos = *itr;
- BLOCKTYPE BlockID = m_World.GetBlock(Pos.x, Pos.y, Pos.z);
- if(!IsAllowedBlock(BlockID))
- continue;
+ if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == a_BlockZ))
+ {
+ return;
+ }
+ }
+
+ m_TotalBlocks += 1;
+ ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ));
+}
+
- BLOCKTYPE BottomBlock = m_World.GetBlock( Pos.x, Pos.y - 1, Pos.z );
-
- if( IsPassable(BottomBlock) )
+
+
+
+bool cSandSimulator::CanStartFallingThrough(BLOCKTYPE a_BlockType)
+{
+ switch (a_BlockType)
+ {
+ case E_BLOCK_AIR:
+ case E_BLOCK_FIRE:
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
{
- cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockID);
- FallingBlock->Initialize(&m_World);
- m_World.SetBlock( Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0 );
+ return true;
}
}
-
+ return false;
}
-bool cSandSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType )
+bool cSandSimulator::CanContinueFallThrough(BLOCKTYPE a_BlockType)
{
- return a_BlockType == E_BLOCK_SAND
- || a_BlockType == E_BLOCK_GRAVEL;
+ switch (a_BlockType)
+ {
+ case E_BLOCK_AIR:
+ case E_BLOCK_FIRE:
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_COBWEB:
+ case E_BLOCK_TALL_GRASS:
+ case E_BLOCK_DEAD_BUSH:
+ case E_BLOCK_YELLOW_FLOWER:
+ case E_BLOCK_RED_ROSE:
+ case E_BLOCK_BROWN_MUSHROOM:
+ case E_BLOCK_RED_MUSHROOM:
+ case E_BLOCK_TORCH:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_CROPS:
+ case E_BLOCK_PUMPKIN_STEM:
+ case E_BLOCK_MELON_STEM:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ case E_BLOCK_WOODEN_BUTTON:
+ case E_BLOCK_WOODEN_PRESSURE_PLATE:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ {
+ return true;
+ }
+ }
+ return false;
}
-void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
+bool cSandSimulator::IsReplacedOnRematerialization(BLOCKTYPE a_BlockType)
{
- // TODO: Optimize this by passing the block type along
- int RelX = a_BlockX;
- int RelY = a_BlockY;
- int RelZ = a_BlockZ;
- int ChunkX, ChunkZ;
- cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
- if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, RelY, RelZ)))
+ switch (a_BlockType)
{
- return;
+ case E_BLOCK_AIR:
+ case E_BLOCK_FIRE:
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ case E_BLOCK_TALL_GRASS:
+ case E_BLOCK_DEAD_BUSH:
+ {
+ return true;
+ }
}
+ return false;
+}
- Vector3i Block(a_BlockX, a_BlockY, a_BlockZ);
-
- //check for duplicates
- for (BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr)
+
+
+
+
+bool cSandSimulator::DoesBreakFallingThrough(BLOCKTYPE a_BlockType)
+{
+ switch (a_BlockType)
{
- Vector3i Pos = *itr;
- if ((Pos.x == a_BlockX) && (Pos.y == a_BlockY) && (Pos.z == a_BlockZ))
+ case E_BLOCK_STONE_SLAB:
+ case E_BLOCK_WOODEN_SLAB:
{
- return;
+ return true;
}
}
+ return false;
+}
+
- m_Blocks->push_back(Block);
+
+
+
+void cSandSimulator::FinishFalling(
+ cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ,
+ BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta
+)
+{
+ ASSERT(a_BlockY < cChunkDef::Height);
+
+ BLOCKTYPE CurrentBlockType = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if ((a_FallingBlockType == E_BLOCK_ANVIL) || IsReplacedOnRematerialization(CurrentBlockType))
+ {
+ // Rematerialize the material here:
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta);
+ return;
+ }
+
+ // Create a pickup instead:
+ cItems Pickups;
+ Pickups.Add((ENUM_ITEM_ID)a_FallingBlockType, 1, a_FallingBlockMeta);
+ a_World->SpawnItemPickups(Pickups, (double)a_BlockX + 0.5, (double)a_BlockY + 0.5, (double)a_BlockZ + 0.5, 0);
}
-bool cSandSimulator::IsPassable(BLOCKTYPE a_BlockType)
+void cSandSimulator::DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
{
- return (a_BlockType == E_BLOCK_AIR)
- || IsBlockWater(a_BlockType)
- || IsBlockLava(a_BlockType)
- || (a_BlockType == E_BLOCK_FIRE);
+ // TODO
}
+
+
+
+
diff --git a/source/Simulator/SandSimulator.h b/source/Simulator/SandSimulator.h
index ebd154f2d..571258049 100644
--- a/source/Simulator/SandSimulator.h
+++ b/source/Simulator/SandSimulator.h
@@ -2,32 +2,62 @@
#pragma once
#include "Simulator.h"
-#include "../BlockEntity.h"
-#include "../Vector3i.h"
-class cSandSimulator : public cSimulator
+/// Despite the class name, this simulator takes care of all blocks that fall when suspended in the air.
+class cSandSimulator :
+ public cSimulator
{
public:
- cSandSimulator(cWorld & a_World);
- ~cSandSimulator();
-
- virtual void Simulate( float a_Dt ) override;
-
- virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override;
- virtual bool IsPassable( BLOCKTYPE a_BlockType );
+ cSandSimulator(cWorld & a_World, cIniFile & a_IniFile);
+
+ // cSimulator overrides:
+ virtual void Simulate(float a_Dt) override {} // Unused in this simulator
+ virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override;
+ virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override;
+
+ /// Returns true if a falling-able block can start falling through the specified block type
+ static bool CanStartFallingThrough(BLOCKTYPE a_BlockType);
+
+ /// Returns true if an already-falling block can pass through the specified block type (e. g. torch)
+ static bool CanContinueFallThrough(BLOCKTYPE a_BlockType);
+
+ /// Returns true if the falling block rematerializing will replace the specified block type (e. g. tall grass)
+ static bool IsReplacedOnRematerialization(BLOCKTYPE a_BlockType);
+
+ /// Returns true if the specified block breaks falling blocks while they fall through it (e. g. halfslabs)
+ static bool DoesBreakFallingThrough(BLOCKTYPE a_BlockType);
+
+ /** Called when a block finishes falling at the specified coords, either by insta-fall,
+ or through cFallingBlock entity.
+ It either rematerializes the block (a_FallingBlockType) at the specified coords, or creates a pickup,
+ based on the block currently present in the world at the dest specified coords
+ */
+ static void FinishFalling(
+ cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ,
+ BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta
+ );
protected:
+ bool m_IsInstantFall; // If set to true, blocks don't fall using cFallingBlock entity, but instantly instead
+
+ int m_TotalBlocks; // Total number of blocks currently in the queue for simulating
+
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
-
- typedef std::list <Vector3i> BlockList;
- BlockList * m_Blocks;
- BlockList * m_Buffer;
+
+ /// Performs the instant fall of the block - removes it from top, Finishes it at the bottom
+ void DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
};
+/// Per-chunk data for the simulator, specified individual chunks to simulate; Data is not used
+typedef cCoordWithIntList cSandSimulatorChunkData;
+
+
+
+
diff --git a/source/World.cpp b/source/World.cpp
index 84874258f..2cfe56d57 100644
--- a/source/World.cpp
+++ b/source/World.cpp
@@ -250,10 +250,10 @@ cWorld::cWorld(const AString & a_WorldName) :
m_BlockTickQueueCopy.reserve(1000);
// Simulators:
- m_SimulatorManager = new cSimulatorManager(*this);
+ m_SimulatorManager = new cSimulatorManager(*this);
m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER);
m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA);
- m_SandSimulator = new cSandSimulator(*this);
+ m_SandSimulator = new cSandSimulator(*this, IniFile);
m_FireSimulator = new cFireSimulator(*this, IniFile);
m_RedstoneSimulator = new cRedstoneSimulator(*this);
@@ -1166,9 +1166,9 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
float SpeedY = (float)(a_FlyAwaySpeed * r1.randInt(1000));
float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(1000) - 500));
cPickup * Pickup = new cPickup(
- (int)(a_BlockX * 32) + r1.randInt(16) + r1.randInt(16),
- (int)(a_BlockY * 32) + r1.randInt(16) + r1.randInt(16),
- (int)(a_BlockZ * 32) + r1.randInt(16) + r1.randInt(16),
+ (int)(a_BlockX * 32) + (r1.randInt(16) + r1.randInt(16) - 16),
+ (int)(a_BlockY * 32) + (r1.randInt(16) + r1.randInt(16) - 16),
+ (int)(a_BlockZ * 32) + (r1.randInt(16) + r1.randInt(16) - 16),
*itr, SpeedX, SpeedY, SpeedZ
);
Pickup->Initialize(this);
diff --git a/source/World.h b/source/World.h
index 2965ae1c3..ed0053db5 100644
--- a/source/World.h
+++ b/source/World.h
@@ -479,7 +479,7 @@ private:
bool m_IsDeepSnowEnabled;
// The cRedstone class simulates redstone and needs access to m_RSList
- friend class cRedstone;
+ // friend class cRedstone;
std::vector<int> m_RSList;
std::vector<BlockTickQueueItem *> m_BlockTickQueue;