Added code for the chunks to manipulate their neighbors while ticking. Also added some basic farming support - melon and pumpkin growing code. Untested and untestable so far, will test and fix later.
git-svn-id: http://mc-server.googlecode.com/svn/trunk@518 0a769ca7-a7f5-676a-18bf-c427514a06d6master
parent
3c97a8e8a5
commit
9d6a5b9ce0
|
@ -213,5 +213,8 @@ dye=351
|
|||
inksac=351:0
|
||||
cactusgreen=351:2
|
||||
shears=359
|
||||
melonslice=360
|
||||
pumpkinseeds=361
|
||||
melonseeds=362
|
||||
goldrecord=2256
|
||||
greenrecord=2257
|
|
@ -65,7 +65,8 @@ enum ENUM_BLOCK_ID
|
|||
E_BLOCK_DIAMOND_BLOCK = 57,
|
||||
E_BLOCK_WORKBENCH = 58,
|
||||
E_BLOCK_CROPS = 59,
|
||||
E_BLOCK_SOIL = 60,
|
||||
E_BLOCK_SOIL = 60, // Deprecated, use E_BLOCK_FARMLAND instead
|
||||
E_BLOCK_FARMLAND = 60,
|
||||
E_BLOCK_FURNACE = 61,
|
||||
E_BLOCK_BURNING_FURNACE = 62,
|
||||
E_BLOCK_SIGN_POST = 63,
|
||||
|
|
114
source/Defines.h
114
source/Defines.h
|
@ -18,7 +18,7 @@ extern bool g_BlockOneHitDig[];
|
|||
inline bool IsValidBlock( int a_BlockID ) //tolua_export
|
||||
{ //tolua_export
|
||||
if( a_BlockID > -1 &&
|
||||
a_BlockID <= 121 && //items to 109 are valid for 1.8.1.. 1.9.5 is up to 121
|
||||
a_BlockID <= 126 && //items to 109 are valid for Beta1.8.1.. 1.2.5 is up to 126
|
||||
//a_BlockID != 29 && allow pistons
|
||||
//a_BlockID != 33 && allow pistons
|
||||
a_BlockID != 34 &&
|
||||
|
@ -29,6 +29,10 @@ inline bool IsValidBlock( int a_BlockID ) //tolua_export
|
|||
return false;
|
||||
} //tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Was old :o
|
||||
// Changed to fit the style ;)
|
||||
inline bool IsValidItem( int a_ItemID ) //tolua_export
|
||||
|
@ -45,16 +49,28 @@ inline bool IsValidItem( int a_ItemID ) //tolua_export
|
|||
return IsValidBlock( a_ItemID );
|
||||
} //tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool IsBlockWater(char a_BlockID)
|
||||
{
|
||||
return (a_BlockID == E_BLOCK_WATER || a_BlockID == E_BLOCK_STATIONARY_WATER);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool IsBlockLava(char a_BlockID)
|
||||
{
|
||||
return (a_BlockID == E_BLOCK_LAVA || a_BlockID == E_BLOCK_STATIONARY_LAVA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline void AddDirection( int & a_X, int & a_Y, int & a_Z, char a_Direction, bool a_bInverse = false )
|
||||
{
|
||||
if( !a_bInverse )
|
||||
|
@ -107,6 +123,10 @@ inline void AddDirection( int & a_X, int & a_Y, int & a_Z, char a_Direction, boo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline void AddDirection( int & a_X, unsigned char & a_Y, int & a_Z, char a_Direction, bool a_bInverse = false ) //tolua_export
|
||||
{//tolua_export
|
||||
int Y = a_Y;
|
||||
|
@ -116,6 +136,10 @@ inline void AddDirection( int & a_X, unsigned char & a_Y, int & a_Z, char a_Dire
|
|||
else a_Y = (unsigned char)Y;
|
||||
}//tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f
|
||||
#define MIN(a,b) (((a)>(b))?(b):(a))
|
||||
|
@ -130,6 +154,10 @@ inline void EulerToVector( float a_Pan, float a_Pitch, float & a_X, float & a_Y,
|
|||
a_Z = sin(a_Pitch / 180 * PI);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline void VectorToEuler( float a_X, float a_Y, float a_Z, float & a_Pan, float & a_Pitch )
|
||||
{
|
||||
if( a_X != 0 )
|
||||
|
@ -139,11 +167,19 @@ inline void VectorToEuler( float a_X, float a_Y, float a_Z, float & a_Pan, float
|
|||
a_Pitch = atan2(a_Y, sqrtf((a_X * a_X) + (a_Z * a_Z))) * 180 / PI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline float GetSignf( float a_Val )
|
||||
{
|
||||
return (a_Val < 0.f)?-1.f:1.f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline float GetSpecialSignf( float a_Val )
|
||||
{
|
||||
return (a_Val <= 0.f)?-1.f:1.f;
|
||||
|
@ -151,36 +187,68 @@ inline float GetSpecialSignf( float a_Val )
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ItemCategory
|
||||
{
|
||||
inline bool IsPickaxe(ENUM_ITEM_ID a_ItemID)
|
||||
{
|
||||
return a_ItemID == E_ITEM_WOODEN_PICKAXE
|
||||
|| a_ItemID == E_ITEM_STONE_PICKAXE
|
||||
|| a_ItemID == E_ITEM_IRON_PICKAXE
|
||||
|| a_ItemID == E_ITEM_GOLD_PICKAXE
|
||||
|| a_ItemID == E_ITEM_DIAMOND_PICKAXE;
|
||||
return (a_ItemID == E_ITEM_WOODEN_PICKAXE)
|
||||
|| (a_ItemID == E_ITEM_STONE_PICKAXE)
|
||||
|| (a_ItemID == E_ITEM_IRON_PICKAXE)
|
||||
|| (a_ItemID == E_ITEM_GOLD_PICKAXE)
|
||||
|| (a_ItemID == E_ITEM_DIAMOND_PICKAXE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool IsAxe(ENUM_ITEM_ID a_ItemID)
|
||||
{
|
||||
return a_ItemID == E_ITEM_WOODEN_AXE
|
||||
|| a_ItemID == E_ITEM_STONE_AXE
|
||||
|| a_ItemID == E_ITEM_IRON_AXE
|
||||
|| a_ItemID == E_ITEM_GOLD_AXE
|
||||
|| a_ItemID == E_ITEM_DIAMOND_AXE;
|
||||
return (a_ItemID == E_ITEM_WOODEN_AXE)
|
||||
|| (a_ItemID == E_ITEM_STONE_AXE)
|
||||
|| (a_ItemID == E_ITEM_IRON_AXE)
|
||||
|| (a_ItemID == E_ITEM_GOLD_AXE)
|
||||
|| (a_ItemID == E_ITEM_DIAMOND_AXE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool IsSword(ENUM_ITEM_ID a_ItemID)
|
||||
{
|
||||
return a_ItemID == E_ITEM_WOODEN_SWORD
|
||||
|| a_ItemID == E_ITEM_STONE_SWORD
|
||||
|| a_ItemID == E_ITEM_IRON_SWORD
|
||||
|| a_ItemID == E_ITEM_GOLD_SWORD
|
||||
|| a_ItemID == E_ITEM_DIAMOND_SWORD;
|
||||
return (a_ItemID == E_ITEM_WOODEN_SWORD)
|
||||
|| (a_ItemID == E_ITEM_STONE_SWORD)
|
||||
|| (a_ItemID == E_ITEM_IRON_SWORD)
|
||||
|| (a_ItemID == E_ITEM_GOLD_SWORD)
|
||||
|| (a_ItemID == E_ITEM_DIAMOND_SWORD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool IsHoe(ENUM_ITEM_ID a_ItemID)
|
||||
{
|
||||
return (a_ItemID == E_ITEM_WOODEN_HOE)
|
||||
|| (a_ItemID == E_ITEM_STONE_HOE)
|
||||
|| (a_ItemID == E_ITEM_IRON_HOE)
|
||||
|| (a_ItemID == E_ITEM_GOLD_HOE)
|
||||
|| (a_ItemID == E_ITEM_DIAMOND_HOE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool IsShovel(ENUM_ITEM_ID a_ItemID)
|
||||
{
|
||||
return (a_ItemID == E_ITEM_WOODEN_SHOVEL)
|
||||
|| (a_ItemID == E_ITEM_STONE_SHOVEL)
|
||||
|| (a_ItemID == E_ITEM_IRON_SHOVEL)
|
||||
|| (a_ItemID == E_ITEM_GOLD_SHOVEL)
|
||||
|| (a_ItemID == E_ITEM_DIAMOND_SHOVEL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//tolua_begin
|
||||
enum eGameMode
|
||||
{
|
||||
|
@ -188,6 +256,10 @@ enum eGameMode
|
|||
eGameMode_Creative = 1,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum eWeather
|
||||
{
|
||||
eWeather_Sunny = 0,
|
||||
|
@ -195,4 +267,12 @@ enum eWeather
|
|||
eWeather_ThunderStorm = 2,
|
||||
|
||||
};
|
||||
//tolua_end
|
||||
|
||||
|
||||
|
||||
|
||||
//tolua_end
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -542,6 +542,16 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
|||
void cChunk::TickBlocks(MTRand & a_TickRandom)
|
||||
{
|
||||
// Tick dem blocks
|
||||
/*
|
||||
// DEBUG:
|
||||
int RandomX = 0;
|
||||
int RandomY = 1;
|
||||
int RandomZ = 0;
|
||||
m_BlockTickX = 0;
|
||||
m_BlockTickY = 40;
|
||||
m_BlockTickZ = 0;
|
||||
*/
|
||||
|
||||
int RandomX = a_TickRandom.randInt();
|
||||
int RandomY = a_TickRandom.randInt();
|
||||
int RandomZ = a_TickRandom.randInt();
|
||||
|
@ -552,41 +562,43 @@ void cChunk::TickBlocks(MTRand & a_TickRandom)
|
|||
m_BlockTickY = (m_BlockTickY + RandomY) % Height;
|
||||
m_BlockTickZ = (m_BlockTickZ + RandomZ) % Width;
|
||||
|
||||
if( m_BlockTickY > m_HeightMap[ m_BlockTickX + m_BlockTickZ * Width ] ) continue; // It's all air up here
|
||||
if (m_BlockTickY > m_HeightMap[ m_BlockTickX + m_BlockTickZ * Width])
|
||||
{
|
||||
continue; // It's all air up here
|
||||
}
|
||||
|
||||
unsigned int Index = MakeIndexNoCheck( m_BlockTickX, m_BlockTickY, m_BlockTickZ );
|
||||
char ID = m_BlockTypes[Index];
|
||||
BLOCKTYPE ID = m_BlockTypes[Index];
|
||||
switch( ID )
|
||||
{
|
||||
/*
|
||||
// TODO: re-enable
|
||||
case E_BLOCK_DIRT:
|
||||
{
|
||||
char AboveBlock = GetBlock( Index+1 );
|
||||
if ( (AboveBlock == 0) && GetNibble( m_BlockSkyLight, Index ) > 0xf/2 ) // Half lit //changed to not allow grass if any one hit object is on top
|
||||
{
|
||||
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetNibble( m_BlockMeta, Index ) );
|
||||
}
|
||||
if ( (g_BlockOneHitDig[AboveBlock]) && GetNibble( m_BlockSkyLight, Index+1 ) > 0xf/2 ) // Half lit //ch$
|
||||
{
|
||||
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetNibble( m_BlockMeta, Index ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
case E_BLOCK_GRASS:
|
||||
{
|
||||
char AboveBlock = GetBlock( Index + (Width * Width) );
|
||||
// Grass turns into dirt if there's another block on top of it:
|
||||
BLOCKTYPE AboveBlock = GetBlock(Index + (Width * Width) );
|
||||
if (!( (AboveBlock == E_BLOCK_AIR) || (g_BlockOneHitDig[AboveBlock]) || (g_BlockTransparent[AboveBlock]) ) )
|
||||
{
|
||||
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_DIRT, GetNibble( m_BlockMeta, Index ) );
|
||||
}
|
||||
|
||||
// TODO: Grass spreads to nearby blocks if there's enough light and free space above that block
|
||||
// Ref.: http://www.minecraftwiki.net/wiki/Grass_Block#Growth
|
||||
break;
|
||||
}
|
||||
|
||||
case E_BLOCK_SAPLING: //todo: check meta of sapling. change m_World->GrowTree to look change trunk and leaves based on meta of sapling
|
||||
case E_BLOCK_CROPS:
|
||||
{
|
||||
NIBBLETYPE Meta = GetMeta(Index);
|
||||
if (Meta < 7)
|
||||
{
|
||||
FastSetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_CROPS, ++Meta);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case E_BLOCK_PUMPKIN_STEM:
|
||||
case E_BLOCK_MELON_STEM: TickMelonPumpkin(m_BlockTickX, m_BlockTickY, m_BlockTickZ, Index, ID, a_TickRandom); break;
|
||||
|
||||
case E_BLOCK_SAPLING:
|
||||
{
|
||||
// Check the highest bit, if set, grow the tree, if not, set it (1-bit delay):
|
||||
NIBBLETYPE Meta = GetMeta(m_BlockTickX, m_BlockTickY, m_BlockTickZ);
|
||||
|
@ -618,6 +630,151 @@ void cChunk::TickBlocks(MTRand & a_TickRandom)
|
|||
|
||||
|
||||
|
||||
void cChunk::TickMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, int a_BlockIdx, BLOCKTYPE a_BlockType, MTRand & a_TickRandom)
|
||||
{
|
||||
NIBBLETYPE Meta = GetMeta(a_BlockIdx);
|
||||
if (Meta < 7)
|
||||
{
|
||||
FastSetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ, a_BlockType, ++Meta);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the stem BlockType into produce BlockType
|
||||
BLOCKTYPE ProduceType;
|
||||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_MELON_STEM: ProduceType = E_BLOCK_MELON; break;
|
||||
case E_BLOCK_PUMPKIN_STEM: ProduceType = E_BLOCK_PUMPKIN; break;
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled blocktype in TickMelonPumpkin()");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there's another melon / pumpkin around that stem, if so, abort:
|
||||
bool IsValid;
|
||||
BLOCKTYPE BlockType[4];
|
||||
NIBBLETYPE BlockMeta; // unused
|
||||
IsValid = UnboundedRelGetBlock(a_RelX + 1, a_RelY, a_RelZ, BlockType[0], BlockMeta);
|
||||
IsValid = IsValid && UnboundedRelGetBlock(a_RelX - 1, a_RelY, a_RelZ, BlockType[1], BlockMeta);
|
||||
IsValid = IsValid && UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ + 1, BlockType[2], BlockMeta);
|
||||
IsValid = IsValid && UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ - 1, BlockType[3], BlockMeta);
|
||||
if (
|
||||
!IsValid ||
|
||||
(BlockType[0] == ProduceType) ||
|
||||
(BlockType[1] == ProduceType) ||
|
||||
(BlockType[2] == ProduceType) ||
|
||||
(BlockType[3] == ProduceType)
|
||||
)
|
||||
{
|
||||
// Neighbors not valid or already taken by the same produce
|
||||
return;
|
||||
}
|
||||
|
||||
// Pick a direction in which to place the produce:
|
||||
int x = 0, z = 0;
|
||||
int CheckType = a_TickRandom.randInt(4); // The index to the neighbors array which should be checked for emptiness
|
||||
switch (CheckType)
|
||||
{
|
||||
case 0: x = 1; break;
|
||||
case 1: x = -1; break;
|
||||
case 2: z = 1; break;
|
||||
case 3: z = -1; break;
|
||||
}
|
||||
|
||||
// Check that the block in that direction is empty:
|
||||
switch (BlockType[CheckType])
|
||||
{
|
||||
case E_BLOCK_AIR:
|
||||
case E_BLOCK_SNOW:
|
||||
case E_BLOCK_TALL_GRASS:
|
||||
case E_BLOCK_DEAD_BUSH:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
|
||||
// Check if there's soil under the neighbor. We already know the neighbors are valid. Place produce if ok
|
||||
BLOCKTYPE Soil;
|
||||
UnboundedRelGetBlock(a_RelX + x, a_RelY, a_RelZ + z, Soil, BlockMeta);
|
||||
switch (Soil)
|
||||
{
|
||||
case E_BLOCK_DIRT:
|
||||
case E_BLOCK_GRASS:
|
||||
case E_BLOCK_FARMLAND:
|
||||
{
|
||||
// Place a randomly-facing produce:
|
||||
UnboundedRelFastSetBlock(a_RelX + x, a_RelY, a_RelZ + z, ProduceType, (NIBBLETYPE)(a_TickRandom.randInt(4) % 4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunk::UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
|
||||
{
|
||||
if ((a_RelX >= 0) && (a_RelX <= cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ <= cChunkDef::Width))
|
||||
{
|
||||
int BlockIdx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
|
||||
a_BlockType = GetBlock(BlockIdx);
|
||||
a_BlockMeta = GetMeta(BlockIdx);
|
||||
return true;
|
||||
}
|
||||
return m_ChunkMap->LockedGetBlock(
|
||||
m_PosX * cChunkDef::Width + a_RelX,
|
||||
ZERO_CHUNK_Y * cChunkDef::Height + a_RelY,
|
||||
m_PosZ * cChunkDef::Width + a_RelZ,
|
||||
a_BlockType, a_BlockMeta
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
if ((a_RelX >= 0) && (a_RelX <= cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ <= cChunkDef::Width))
|
||||
{
|
||||
SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta);
|
||||
return true;
|
||||
}
|
||||
return m_ChunkMap->LockedSetBlock(
|
||||
m_PosX * cChunkDef::Width + a_RelX,
|
||||
ZERO_CHUNK_Y * cChunkDef::Height + a_RelY,
|
||||
m_PosZ * cChunkDef::Width + a_RelZ,
|
||||
a_BlockType, a_BlockMeta
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunk::UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
if ((a_RelX >= 0) && (a_RelX <= cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ <= cChunkDef::Width))
|
||||
{
|
||||
FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta);
|
||||
return true;
|
||||
}
|
||||
return m_ChunkMap->LockedFastSetBlock(
|
||||
m_PosX * cChunkDef::Width + a_RelX,
|
||||
ZERO_CHUNK_Y * cChunkDef::Height + a_RelY,
|
||||
m_PosZ * cChunkDef::Width + a_RelZ,
|
||||
a_BlockType, a_BlockMeta
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cChunk::GetHeight( int a_X, int a_Z )
|
||||
{
|
||||
ASSERT((a_X >= 0) && (a_X < Width) && (a_Z >= 0) && (a_Z < Width));
|
||||
|
@ -704,176 +861,6 @@ void cChunk::CalculateHeightmap()
|
|||
|
||||
|
||||
|
||||
void cChunk::CalculateLighting()
|
||||
{
|
||||
// Calculate sunlight
|
||||
memset(m_BlockSkyLight, 0xff, NumBlocks / 2 ); // Set all to fully lit, so everything above HeightMap is lit
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
for (int z = 0; z < Width; z++)
|
||||
{
|
||||
char sunlight = 0xf;
|
||||
for (int y = m_HeightMap[x + z*Width]; y > -1; y--)
|
||||
{
|
||||
int index = MakeIndexNoCheck(x, y, z);
|
||||
|
||||
if( g_BlockTransparent[ (int)m_BlockTypes[index] ] == false )
|
||||
{
|
||||
sunlight = 0x0;
|
||||
}
|
||||
SetNibble( m_BlockSkyLight, index, sunlight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate blocklights
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
for (int z = 0; z < Width; z++)
|
||||
{
|
||||
int MaxHeight = m_HeightMap[x + z * Width];
|
||||
for (int y = 0; y < MaxHeight; y++)
|
||||
{
|
||||
char BlockID = GetBlock(x, y, z);
|
||||
SetNibble( m_BlockLight, x, y, z, g_BlockLightValue[(int)BlockID] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpreadLight(m_BlockSkyLight);
|
||||
SpreadLight(m_BlockLight);
|
||||
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunk::SpreadLight(NIBBLETYPE * a_LightBuffer)
|
||||
{
|
||||
// Spread the light
|
||||
for(int x = 0; x < Width; x++) for(int z = 0; z < Width; z++) for(int y = 0; y < Height; y++)
|
||||
{
|
||||
int index = MakeIndexNoCheck(x, y, z);
|
||||
if( g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] > 0 )
|
||||
{
|
||||
SpreadLightOfBlock(a_LightBuffer, x, y, z, g_BlockSpreadLightFalloff[ m_BlockTypes[index] ]);
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = Width-1; x > -1; x--) for(int z = Width-1; z > -1; z--) for(int y = Height-1; y > -1; y--)
|
||||
{
|
||||
int index = MakeIndexNoCheck(x, y, z);
|
||||
if( g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] > 0 )
|
||||
{
|
||||
SpreadLightOfBlock(a_LightBuffer, x, y, z, g_BlockSpreadLightFalloff[ m_BlockTypes[index] ]);
|
||||
}
|
||||
}
|
||||
|
||||
bool bCalcLeft, bCalcRight, bCalcFront, bCalcBack;
|
||||
bCalcLeft = bCalcRight = bCalcFront = bCalcBack = false;
|
||||
|
||||
// Spread to neighbour chunks X-axis
|
||||
cChunkPtr LeftChunk = m_ChunkMap->GetChunkNoGen( m_PosX - 1, m_PosY, m_PosZ );
|
||||
cChunkPtr RightChunk = m_ChunkMap->GetChunkNoGen( m_PosX + 1, m_PosY, m_PosZ );
|
||||
NIBBLETYPE * LeftSky = NULL, * RightSky = NULL;
|
||||
if (LeftChunk->IsValid())
|
||||
{
|
||||
LeftSky = (a_LightBuffer == m_BlockSkyLight) ? LeftChunk->m_BlockSkyLight : LeftChunk->m_BlockLight;
|
||||
}
|
||||
if (RightChunk->IsValid())
|
||||
{
|
||||
RightSky = (a_LightBuffer == m_BlockSkyLight) ? RightChunk->m_BlockSkyLight : RightChunk->m_BlockLight;
|
||||
}
|
||||
|
||||
for (int z = 0; z < Width; z++) for(int y = 0; y < Height; y++)
|
||||
{
|
||||
if (LeftSky != NULL)
|
||||
{
|
||||
int index = MakeIndexNoCheck( 0, y, z );
|
||||
if( g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] > 0 )
|
||||
{
|
||||
BLOCKTYPE CurrentLight = GetNibble( a_LightBuffer, 0, y, z );
|
||||
BLOCKTYPE LeftLight = GetNibble( LeftSky, Width-1, y, z );
|
||||
if( LeftLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] )
|
||||
{
|
||||
SetNibble( LeftSky, Width - 1, y, z, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ]) );
|
||||
bCalcLeft = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RightSky != NULL)
|
||||
{
|
||||
int index = MakeIndexNoCheck( Width - 1, y, z );
|
||||
if( g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] > 0 )
|
||||
{
|
||||
BLOCKTYPE CurrentLight = GetNibble( a_LightBuffer, Width-1, y, z );
|
||||
BLOCKTYPE RightLight = GetNibble( RightSky, 0, y, z );
|
||||
if( RightLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] )
|
||||
{
|
||||
SetNibble( RightSky, 0, y, z, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ]) );
|
||||
bCalcRight = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spread to neighbour chunks Z-axis
|
||||
cChunkPtr FrontChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ - 1 );
|
||||
cChunkPtr BackChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ + 1 );
|
||||
NIBBLETYPE * FrontSky = NULL, * BackSky = NULL;
|
||||
if (FrontChunk->IsValid())
|
||||
{
|
||||
FrontSky = (a_LightBuffer == m_BlockSkyLight) ? FrontChunk->m_BlockSkyLight : FrontChunk->m_BlockLight;
|
||||
}
|
||||
if (BackChunk->IsValid())
|
||||
{
|
||||
BackSky = (a_LightBuffer == m_BlockSkyLight) ? BackChunk->m_BlockSkyLight : BackChunk->m_BlockLight;
|
||||
}
|
||||
for(int x = 0; x < Width; x++) for(int y = 0; y < Height; y++)
|
||||
{
|
||||
if (FrontSky != NULL)
|
||||
{
|
||||
int index = MakeIndexNoCheck( x, y, 0 );
|
||||
if( g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] > 0 )
|
||||
{
|
||||
BLOCKTYPE CurrentLight = GetNibble( a_LightBuffer, x, y, 0 );
|
||||
BLOCKTYPE FrontLight = GetNibble( FrontSky, x, y, Width-1 );
|
||||
if( FrontLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] )
|
||||
{
|
||||
SetNibble( FrontSky, x, y, Width-1, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ]) );
|
||||
bCalcFront = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (BackSky != NULL)
|
||||
{
|
||||
int index = MakeIndexNoCheck( x, y, Width-1 );
|
||||
if( g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] > 0 )
|
||||
{
|
||||
BLOCKTYPE CurrentLight = GetNibble( a_LightBuffer, x, y, Width-1 );
|
||||
BLOCKTYPE BackLight = GetNibble( BackSky, x, y, 0 );
|
||||
if ( BackLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ] )
|
||||
{
|
||||
SetNibble( BackSky, x, y, 0, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockTypes[index] ]) );
|
||||
bCalcBack = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( bCalcLeft ) m_World->ReSpreadLighting( m_PosX - 1, m_PosY, m_PosZ );
|
||||
if ( bCalcRight ) m_World->ReSpreadLighting( m_PosX + 1, m_PosY, m_PosZ );
|
||||
if ( bCalcFront ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ - 1 );
|
||||
if ( bCalcBack ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ + 1 );
|
||||
// No need to set those neighbors dirty, they will recalc their light anyway so they'll get marked dirty there
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunk::SetBlock( int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta )
|
||||
{
|
||||
if (a_RelX < 0 || a_RelX >= Width || a_RelY < 0 || a_RelY >= Height || a_RelZ < 0 || a_RelZ >= Width)
|
||||
|
|
|
@ -108,7 +108,6 @@ public:
|
|||
void Stay(bool a_Stay = true);
|
||||
|
||||
void Tick(float a_Dt, MTRand & a_TickRandom);
|
||||
void TickBlocks(MTRand & a_TickRandom);
|
||||
|
||||
int GetPosX() { return m_PosX; }
|
||||
int GetPosY() { return m_PosY; }
|
||||
|
@ -172,12 +171,9 @@ public:
|
|||
m_IsSaving = false;
|
||||
}
|
||||
|
||||
inline void SpreadBlockSkyLight(void) {SpreadLight(m_BlockSkyLight); }
|
||||
inline void SpreadBlockLight (void) {SpreadLight(m_BlockLight); }
|
||||
|
||||
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
|
||||
inline NIBBLETYPE GetMeta(int a_BlockIdx) {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
|
||||
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
|
||||
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
|
||||
inline NIBBLETYPE GetMeta(int a_BlockIdx) {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
|
||||
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
|
||||
|
||||
inline NIBBLETYPE GetLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
|
||||
inline NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
|
||||
|
@ -233,7 +229,17 @@ private:
|
|||
// Makes a copy of the list
|
||||
cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
|
||||
|
||||
void SpreadLight(NIBBLETYPE * a_LightBuffer);
|
||||
void TickBlocks(MTRand & a_TickRandom);
|
||||
void TickMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, int a_BlockIdx, BLOCKTYPE a_BlockType, MTRand & a_TickRandom);
|
||||
|
||||
/// Same as GetBlock(), but relative coords needn't be in this chunk (uses m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
||||
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
||||
|
||||
/// Same as SetBlock(), but relative coords needn't be in this chunk (uses m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
||||
bool UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
|
||||
/// Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
||||
bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
};
|
||||
|
||||
typedef cChunk * cChunkPtr;
|
||||
|
|
|
@ -176,6 +176,65 @@ cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
|||
|
||||
|
||||
|
||||
bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
|
||||
{
|
||||
// We already have m_CSLayers locked since this can be called only from within the tick thread
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
|
||||
a_BlockType = Chunk->GetBlock(Index);
|
||||
a_BlockMeta = Chunk->GetMeta(Index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunkMap::LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
// We already have m_CSLayers locked since this can be called only from within the tick thread
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Chunk->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
// We already have m_CSLayers locked since this can be called only from within the tick thread
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Chunk->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cPacket & a_Packet, cClientHandle * a_Exclude)
|
||||
{
|
||||
// Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude
|
||||
|
@ -399,21 +458,6 @@ bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|||
|
||||
|
||||
|
||||
void cChunkMap::SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
if ((Chunk != NULL) && Chunk->IsValid())
|
||||
{
|
||||
Chunk->SpreadBlockSkyLight();
|
||||
Chunk->SpreadBlockLight();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
|
|
|
@ -84,7 +84,6 @@ public:
|
|||
|
||||
bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
bool HasChunkAnyClients (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
void SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
int GetHeight (int a_BlockX, int a_BlockZ);
|
||||
void FastSetBlocks (sSetBlockList & a_BlockList);
|
||||
void CollectPickupsByPlayer(cPlayer * a_Player);
|
||||
|
@ -164,7 +163,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
friend class cChunk; // Temporary (until we have a separate Lighting thread), so that cChunk's lighting calc can ask for neighbor chunks
|
||||
friend class cChunk; // The chunks can manipulate neighbors while in their Tick() method, using LockedGetBlock() and LockedSetBlock()
|
||||
|
||||
class cChunkLayer
|
||||
{
|
||||
|
@ -215,6 +214,15 @@ private:
|
|||
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
|
||||
cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Doesn't load, doesn't generate
|
||||
|
||||
/// Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
||||
|
||||
/// Sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
bool LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
|
||||
/// Fast-sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
bool LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -903,7 +903,9 @@ void cClientHandle::HandleBlockPlace(cPacket_BlockPlace * a_Packet)
|
|||
|
||||
if ((Equipped.m_ItemID != a_Packet->m_ItemType)) // Not valid
|
||||
{
|
||||
LOGWARN("Player %s tried to place a block that was not selected! (could indicate bot)", m_Username.c_str());
|
||||
LOGWARN("Player %s tried to place a block that was not equipped (exp %d, got %d)",
|
||||
m_Username.c_str(), Equipped.m_ItemID, a_Packet->m_ItemType
|
||||
);
|
||||
// TODO: We should probably send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block
|
||||
return;
|
||||
}
|
||||
|
@ -1311,70 +1313,7 @@ void cClientHandle::HandleBlockPlace(cPacket_BlockPlace * a_Packet)
|
|||
}
|
||||
|
||||
// Check whether selected item is allowed to be placed on specific surface
|
||||
bool bIllegalSurface = false;
|
||||
ENUM_BLOCK_ID SurfaceBlock = (ENUM_BLOCK_ID)m_Player->GetWorld()->GetBlock(X, Y-1, Z);
|
||||
switch (a_Packet->m_ItemType)
|
||||
{
|
||||
case E_BLOCK_YELLOW_FLOWER: // Can ONLY be placed on dirt/grass
|
||||
case E_BLOCK_RED_ROSE:
|
||||
case E_BLOCK_SAPLING:
|
||||
{
|
||||
switch (SurfaceBlock)
|
||||
{
|
||||
case E_BLOCK_DIRT:
|
||||
case E_BLOCK_GRASS:
|
||||
{
|
||||
bIllegalSurface = false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bIllegalSurface = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case E_BLOCK_BROWN_MUSHROOM: // Can be placed on pretty much anything, with exceptions
|
||||
case E_BLOCK_RED_MUSHROOM:
|
||||
{
|
||||
switch (SurfaceBlock)
|
||||
{
|
||||
case E_BLOCK_GLASS:
|
||||
case E_BLOCK_YELLOW_FLOWER:
|
||||
case E_BLOCK_RED_ROSE:
|
||||
case E_BLOCK_BROWN_MUSHROOM:
|
||||
case E_BLOCK_RED_MUSHROOM:
|
||||
case E_BLOCK_CACTUS:
|
||||
{
|
||||
bIllegalSurface = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case E_BLOCK_CACTUS:
|
||||
{
|
||||
bIllegalSurface = (SurfaceBlock != E_BLOCK_SAND) && (SurfaceBlock != E_BLOCK_CACTUS); // Cactus can only be placed on sand and itself
|
||||
|
||||
// Check surroundings. Cacti may ONLY be surrounded by air
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
if (
|
||||
(World->GetBlock(X - 1, Y, Z) != E_BLOCK_AIR) ||
|
||||
(World->GetBlock(X + 1, Y, Z) != E_BLOCK_AIR) ||
|
||||
(World->GetBlock(X, Y, Z - 1) != E_BLOCK_AIR) ||
|
||||
(World->GetBlock(X, Y, Z + 1) != E_BLOCK_AIR)
|
||||
)
|
||||
{
|
||||
bIllegalSurface = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // switch (a_Packet->m_ItemType)
|
||||
|
||||
if (bIllegalSurface)
|
||||
if (!m_Player->GetWorld()->IsPlacingItemLegal(a_Packet->m_ItemType, X, Y, Z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -360,6 +360,81 @@ void cWorld::CastThunderbolt ( int a_X, int a_Y, int a_Z )
|
|||
|
||||
|
||||
|
||||
bool cWorld::IsPlacingItemLegal(Int16 a_ItemType, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
BLOCKTYPE SurfaceBlock = GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
|
||||
switch (a_ItemType)
|
||||
{
|
||||
case E_BLOCK_YELLOW_FLOWER: // Can ONLY be placed on dirt/grass
|
||||
case E_BLOCK_RED_ROSE:
|
||||
case E_BLOCK_SAPLING:
|
||||
{
|
||||
switch (SurfaceBlock)
|
||||
{
|
||||
case E_BLOCK_DIRT:
|
||||
case E_BLOCK_GRASS:
|
||||
case E_BLOCK_FARMLAND:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case E_BLOCK_BROWN_MUSHROOM: // Can be placed on pretty much anything, with exceptions
|
||||
case E_BLOCK_RED_MUSHROOM:
|
||||
{
|
||||
switch (SurfaceBlock)
|
||||
{
|
||||
case E_BLOCK_GLASS:
|
||||
case E_BLOCK_YELLOW_FLOWER:
|
||||
case E_BLOCK_RED_ROSE:
|
||||
case E_BLOCK_BROWN_MUSHROOM:
|
||||
case E_BLOCK_RED_MUSHROOM:
|
||||
case E_BLOCK_CACTUS:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case E_BLOCK_CACTUS:
|
||||
{
|
||||
if ((SurfaceBlock != E_BLOCK_SAND) && (SurfaceBlock != E_BLOCK_CACTUS))
|
||||
{
|
||||
// Cactus can only be placed on sand and itself
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check surroundings. Cacti may ONLY be surrounded by air
|
||||
if (
|
||||
(GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) != E_BLOCK_AIR) ||
|
||||
(GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) != E_BLOCK_AIR) ||
|
||||
(GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) != E_BLOCK_AIR) ||
|
||||
(GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) != E_BLOCK_AIR)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case E_ITEM_SEEDS:
|
||||
case E_ITEM_MELON_SEEDS:
|
||||
case E_ITEM_PUMPKIN_SEEDS:
|
||||
{
|
||||
// Seeds can go only on the farmland block:
|
||||
return (SurfaceBlock == E_BLOCK_FARMLAND);
|
||||
}
|
||||
} // switch (a_Packet->m_ItemType)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorld::InitializeSpawn(void)
|
||||
{
|
||||
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
|
||||
|
@ -1463,27 +1538,6 @@ void cWorld::SaveAllChunks(void)
|
|||
|
||||
|
||||
|
||||
void cWorld::ReSpreadLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CSLighting);
|
||||
m_SpreadQueue.remove(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||
m_SpreadQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorld::RemoveSpread(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CSLighting);
|
||||
m_SpreadQueue.remove(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Get and set */
|
||||
/************************************************************************/
|
||||
|
|
|
@ -278,9 +278,6 @@ public:
|
|||
|
||||
void Tick(float a_Dt);
|
||||
|
||||
void ReSpreadLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
void RemoveSpread(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
void InitializeSpawn();
|
||||
|
||||
void CastThunderbolt (int a_X, int a_Y, int a_Z); //tolua_export
|
||||
|
@ -291,6 +288,8 @@ public:
|
|||
cWorldStorage & GetStorage (void) { return m_Storage; }
|
||||
cChunkMap * GetChunkMap (void) { return m_ChunkMap; }
|
||||
|
||||
bool IsPlacingItemLegal(Int16 a_ItemType, int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
private:
|
||||
|
||||
friend class cRoot;
|
||||
|
@ -344,9 +343,6 @@ private:
|
|||
cClientHandleList m_Clients;
|
||||
cPlayerList m_Players;
|
||||
|
||||
cCriticalSection m_CSLighting;
|
||||
cChunkCoordsList m_SpreadQueue;
|
||||
|
||||
cCriticalSection m_CSFastSetBlock;
|
||||
sSetBlockList m_FastSetBlockQueue;
|
||||
|
||||
|
|
Loading…
Reference in New Issue