Merge branch 'master' into MobSpawner

Conflicts:
	MCServer/Plugins/Core
This commit is contained in:
Howaner
2014-11-18 14:56:32 +01:00
415 changed files with 11981 additions and 12491 deletions
+17 -7
View File
@@ -17,15 +17,25 @@ public:
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Don't drop anything
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SAND);
if (a_RelY <= 0)
{
return false;
}
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
switch (BelowBlock)
{
case E_BLOCK_CLAY:
case E_BLOCK_HARDENED_CLAY:
case E_BLOCK_STAINED_CLAY:
case E_BLOCK_SAND:
{
return true;
}
default: return false;
}
}
} ;
+11 -3
View File
@@ -21,7 +21,15 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0));
if (a_BlockMeta == E_META_DIRT_COARSE)
{
// Drop the coarse block (dirt, meta 1)
a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE);
}
else
{
a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL);
}
}
@@ -64,7 +72,7 @@ public:
int BlockY = a_RelY + OfsY;
int BlockZ = a_RelZ + OfsZ;
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(BlockX, BlockZ);
if (Chunk == NULL)
if (Chunk == nullptr)
{
// Unloaded chunk
continue;
@@ -81,7 +89,7 @@ public:
Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta);
if (cBlockInfo::GetHandler(AboveDest)->CanDirtGrowGrass(AboveMeta))
{
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(Chunk->GetWorld(), Chunk->GetPosX() * cChunkDef::Width + BlockX, BlockY, Chunk->GetPosZ() * cChunkDef::Width + BlockZ, ssGrassSpread))
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*Chunk->GetWorld(), Chunk->GetPosX() * cChunkDef::Width + BlockX, BlockY, Chunk->GetPosZ() * cChunkDef::Width + BlockZ, ssGrassSpread))
{
Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
}
+60 -2
View File
@@ -55,7 +55,49 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem((m_BlockType == E_BLOCK_WOODEN_DOOR) ? E_ITEM_WOODEN_DOOR : E_ITEM_IRON_DOOR, 1, 0));
switch (m_BlockType)
{
case E_BLOCK_WOODEN_DOOR:
{
a_Pickups.Add(E_ITEM_WOODEN_DOOR);
break;
}
case E_BLOCK_ACACIA_DOOR:
{
a_Pickups.Add(E_ITEM_ACACIA_DOOR);
break;
}
case E_BLOCK_BIRCH_DOOR:
{
a_Pickups.Add(E_ITEM_BIRCH_DOOR);
break;
}
case E_BLOCK_DARK_OAK_DOOR:
{
a_Pickups.Add(E_ITEM_DARK_OAK_DOOR);
break;
}
case E_BLOCK_JUNGLE_DOOR:
{
a_Pickups.Add(E_ITEM_JUNGLE_DOOR);
break;
}
case E_BLOCK_SPRUCE_DOOR:
{
a_Pickups.Add(E_ITEM_SPRUCE_DOOR);
break;
}
case E_BLOCK_IRON_DOOR:
{
a_Pickups.Add(E_ITEM_IRON_DOOR);
break;
}
default:
{
ASSERT(!"Unhandled door type!");
break;
}
}
}
@@ -131,7 +173,23 @@ public:
/** Returns true if the specified blocktype is any kind of door */
inline static bool IsDoor(BLOCKTYPE a_Block)
{
return (a_Block == E_BLOCK_WOODEN_DOOR) || (a_Block == E_BLOCK_IRON_DOOR);
switch (a_Block)
{
case E_BLOCK_ACACIA_DOOR:
case E_BLOCK_BIRCH_DOOR:
case E_BLOCK_DARK_OAK_DOOR:
case E_BLOCK_IRON_DOOR:
case E_BLOCK_JUNGLE_DOOR:
case E_BLOCK_SPRUCE_DOOR:
case E_BLOCK_WOODEN_DOOR:
{
return true;
}
default:
{
return false;
}
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.Add(E_BLOCK_FENCE_GATE, 1, 0); // Reset meta to zero
a_Pickups.Add(m_BlockType, 1, 0); // Reset meta to zero
}
+7 -7
View File
@@ -4,6 +4,7 @@
#include "../Item.h"
#include "../World.h"
#include "../Chunk.h"
#include "BlockPluginInterface.h"
#include "BlockAnvil.h"
#include "BlockBed.h"
#include "BlockBigFlower.h"
@@ -36,7 +37,6 @@
#include "BlockGlass.h"
#include "BlockGlowstone.h"
#include "BlockGravel.h"
#include "BlockHayBale.h"
#include "BlockMobHead.h"
#include "BlockHopper.h"
#include "BlockIce.h"
@@ -83,7 +83,6 @@
#include "BlockWorkbench.h"
#include "BlockPluginInterface.h"
@@ -100,9 +99,9 @@ public:
for (BLOCKTYPE Type = 0; Type < E_BLOCK_MAX_TYPE_ID; Type++)
{
cBlockHandler * Handler = cBlockInfo::GetHandler(Type);
if (Handler == NULL)
if (Handler == nullptr)
{
printf("NULL handler for block type %d!\n", Type);
printf("nullptr handler for block type %d!\n", Type);
continue;
}
AString BlockName = ItemTypeToString(Type);
@@ -231,7 +230,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE 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 cBlockHayBaleHandler (a_BlockType);
case E_BLOCK_HAY_BALE: return new cBlockSidewaysHandler (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);
@@ -294,6 +293,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_SIGN_POST: return new cBlockSignPostHandler (a_BlockType);
case E_BLOCK_SNOW: return new cBlockSnowHandler (a_BlockType);
case E_BLOCK_SPRUCE_DOOR: return new cBlockDoorHandler (a_BlockType);
case E_BLOCK_SPRUCE_FENCE_GATE: return new cBlockFenceGateHandler (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);
@@ -441,7 +441,7 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
if (a_CanDrop)
{
if ((a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0))
if ((a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0))
{
switch (m_BlockType)
{
@@ -562,7 +562,7 @@ void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterf
{
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, NULL, BlockX, a_RelY, BlockZ);
DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ);
}
a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0);
+1 -1
View File
@@ -78,7 +78,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
/** Handles the dropping, but not destruction, of a block based on what ConvertTo(Verbatim)Pickups() returns, including the spawning of pickups and alertion of plugins
@param a_Digger The entity causing the drop; it may be NULL
@param a_Digger The entity causing the drop; it may be nullptr
@param a_CanDrop Informs the handler whether the block should be dropped at all. One example when this is false is when stone is destroyed by hand
@param a_DropVerbatim Calls ConvertToVerbatimPickups() instead of its counterpart, meaning the block itself is dropped by default (due to a speical tool or enchantment)
*/
-22
View File
@@ -1,22 +0,0 @@
#pragma once
#include "BlockSideways.h"
class cBlockHayBaleHandler :
public cBlockSidewaysHandler
{
public:
cBlockHayBaleHandler(BLOCKTYPE a_BlockType)
: cBlockSidewaysHandler(a_BlockType)
{
}
} ;
+1 -1
View File
@@ -109,7 +109,7 @@ public:
}
// Decay the leaves:
DropBlock(a_ChunkInterface, a_WorldInterface, a_PluginInterface, NULL, BlockX, a_RelY, BlockZ);
DropBlock(a_ChunkInterface, a_WorldInterface, a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ);
a_ChunkInterface.DigBlock(a_WorldInterface, BlockX, a_RelY, BlockZ);
}
} ;
+29 -7
View File
@@ -1,9 +1,9 @@
#pragma once
#include "BlockHandler.h"
#include "../Chunk.h"
#include "MetaRotator.h"
#include "BlockSlab.h"
class cBlockLeverHandler :
@@ -93,13 +93,35 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
NIBBLETYPE Meta;
a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta);
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
eBlockFace Face = BlockMetaDataToBlockFace(Meta);
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true);
return (a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn);
if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height -1))
{
return false;
}
BLOCKTYPE BlockIsOn;
a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockIsOn, Meta);
if (cBlockInfo::FullyOccupiesVoxel(BlockIsOn))
{
return true;
}
else if (cBlockSlabHandler::IsAnySlabType(BlockIsOn))
{
// Check if the slab is turned up side down
if (((Meta & 0x08) == 0x08) && (Face == BLOCK_FACE_TOP))
{
return true;
}
}
return false;
}
+1 -1
View File
@@ -139,7 +139,7 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ,
{
cChunkInterface ChunkInterface(a_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*a_World);
Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, NULL, a_BlockX, a_BlockY, a_BlockZ);
Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, nullptr, a_BlockX, a_BlockY, a_BlockZ);
}
}
+4
View File
@@ -100,6 +100,7 @@ private:
case E_BLOCK_BREWING_STAND:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DAYLIGHT_SENSOR:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_ENCHANTMENT_TABLE:
@@ -108,6 +109,7 @@ private:
// Notice the lack of an E_BLOCK_ENDER_CHEST here; its because ender chests can totally be pushed/pulled in MCS :)
case E_BLOCK_FURNACE:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_INVERTED_DAYLIGHT_SENSOR:
case E_BLOCK_HOPPER:
case E_BLOCK_JUKEBOX:
case E_BLOCK_MOB_SPAWNER:
@@ -115,7 +117,9 @@ private:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_OBSIDIAN:
case E_BLOCK_PISTON_EXTENSION:
case E_BLOCK_STANDING_BANNER:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_WALL_BANNER:
{
return false;
}
+10 -1
View File
@@ -1,7 +1,11 @@
#pragma once
/** This interface is used to decouple block handlers from the cPluginManager dependancy through cWorld.
/** This interface is used to decouple block handlers from the cPluginManager dependency through cWorld.
The block handlers call this interface, which is then implemented by the specific classes that
the caller provides.
*/
@@ -10,5 +14,10 @@ class cBlockPluginInterface
public:
virtual ~cBlockPluginInterface() {}
virtual bool CallHookBlockSpread(int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0;
virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
};
+25 -2
View File
@@ -3,6 +3,7 @@
#include "BlockHandler.h"
#include "../World.h"
#include "BlockSlab.h"
@@ -16,11 +17,33 @@ public:
: cBlockHandler(a_BlockType)
{
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)));
if (a_RelY <= 0)
{
return false;
}
BLOCKTYPE BelowBlock;
NIBBLETYPE BelowBlockMeta;
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta);
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
{
return true;
}
else if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
{
// Check if the slab is turned up side down
if ((BelowBlockMeta & 0x08) == 0x08)
{
return true;
}
}
return false;
}
+24 -1
View File
@@ -5,6 +5,7 @@
#include "Chunk.h"
#include "MetaRotator.h"
#include "ChunkInterface.h"
#include "BlockSlab.h"
@@ -44,6 +45,7 @@ public:
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
@@ -59,7 +61,28 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return ((a_RelY > 0) && cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)));
if (a_RelY <= 0)
{
return false;
}
BLOCKTYPE BelowBlock;
NIBBLETYPE BelowBlockMeta;
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta);
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
{
return true;
}
else if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
{
// Check if the slab is turned up side down
if ((BelowBlockMeta & 0x08) == 0x08)
{
return true;
}
}
return false;
}
+1 -1
View File
@@ -35,7 +35,7 @@ public:
}
BLOCKTYPE Type = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
return ((Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type));
return ((Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type));
}
+1
View File
@@ -13,6 +13,7 @@
#include "../Items/ItemHandler.h"
#include "Root.h"
#include "ChunkInterface.h"
#include "../Entities/Player.h"
+8 -3
View File
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "BlockID.h"
@@ -18,9 +18,14 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_COBBLESTONE, 1, 0));
if (a_BlockMeta == E_META_STONE_STONE)
{
a_Pickups.push_back(cItem(E_BLOCK_COBBLESTONE, 1, 0));
return;
}
a_Pickups.push_back(cItem(E_BLOCK_STONE, 1, a_BlockMeta));
}
} ;
};
+39 -11
View File
@@ -2,6 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "ChunkInterface.h"
@@ -10,6 +11,7 @@
class cBlockTallGrassHandler :
public cBlockHandler
{
typedef cBlockHandler super;
public:
cBlockTallGrassHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
@@ -26,32 +28,58 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Drop seeds, sometimes
MTRand r1;
if (r1.randInt(10) == 5)
cFastRandom Random;
if (Random.NextInt(8) == 0)
{
a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0));
}
}
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if ((!a_Player->IsGameModeCreative()) && (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SHEARS))
if (a_CanDrop && (a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS))
{
cItems Pickups;
Pickups.Add(E_BLOCK_TALL_GRASS, 1, Meta);
a_WorldInterface.SpawnItemPickups(Pickups, a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
cItems Drops;
Drops.Add(m_BlockType, 1, Meta);
a_Player->UseEquippedItem();
// Allow plugins to modify the pickups:
a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops);
// Spawn the pickups:
if (!Drops.empty())
{
MTRand r1;
// Mid-block position first
double MicroX, MicroY, MicroZ;
MicroX = a_BlockX + 0.5;
MicroY = a_BlockY + 0.5;
MicroZ = a_BlockZ + 0.5;
// Add random offset second
MicroX += r1.rand(1) - 0.5;
MicroZ += r1.rand(1) - 0.5;
a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ);
}
return;
}
super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR));
if (a_RelY <= 0)
{
return false;
}
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
return IsBlockTypeOfDirt(BelowBlock);
}
} ;
+52 -64
View File
@@ -24,32 +24,23 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
// Find proper placement of torch
BLOCKTYPE Block;
NIBBLETYPE Meta;
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block
a_ChunkInterface.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, Meta);
if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM))
if (!CanBePlacedOn(Block, Meta, a_BlockFace)) // Try to preserve original direction
{
a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Top or bottom faces clicked, find a suitable face
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block
a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Set a_BlockFace to a valid direction which will be converted later to a metadata
if (a_BlockFace == BLOCK_FACE_NONE)
{
// Client wouldn't have sent anything anyway, but whatever
// No attachable face found - don't place the torch
return false;
}
}
else
{
// Not top or bottom faces, try to preserve whatever face was clicked
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block
if (!CanBePlacedOn(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ), a_BlockFace))
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
if (a_BlockFace == BLOCK_FACE_NONE)
{
return false;
}
}
}
a_BlockType = m_BlockType;
a_BlockMeta = DirectionToMetaData(a_BlockFace);
@@ -97,44 +88,59 @@ public:
}
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, eBlockFace a_BlockFace)
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace)
{
if (!cBlockInfo::FullyOccupiesVoxel(a_BlockType))
switch (a_BlockType)
{
return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle
}
else
{
return true;
case E_BLOCK_END_PORTAL_FRAME:
case E_BLOCK_SOULSAND:
{
// Exceptional vanilla behaviour
return true;
}
case E_BLOCK_GLASS:
case E_BLOCK_STAINED_GLASS:
case E_BLOCK_FENCE:
case E_BLOCK_NETHER_BRICK_FENCE:
case E_BLOCK_COBBLESTONE_WALL:
{
// Torches can only be placed on top of these blocks
return (a_BlockFace == BLOCK_FACE_YP);
}
case E_BLOCK_STONE_SLAB:
case E_BLOCK_WOODEN_SLAB:
{
// Toches can be placed on the top of these slabs only if the occupy the top half of the voxel
return ((a_BlockFace == BLOCK_FACE_YP) && ((a_BlockMeta & 0x08) == 0x08));
}
default:
{
if (cBlockInfo::FullyOccupiesVoxel(a_BlockType))
{
// Torches can be placed on all sides of full blocks except the bottom
return (a_BlockFace != BLOCK_FACE_YM);
}
return false;
}
}
}
/// Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure
/** Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure */
static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all directions
{
eBlockFace Face = static_cast<eBlockFace>(i);
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, true);
BLOCKTYPE BlockInQuestion = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
BLOCKTYPE BlockInQuestion;
NIBBLETYPE BlockInQuestionMeta;
a_ChunkInterface.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockInQuestion, BlockInQuestionMeta);
// If on a block that can only hold a torch if torch is standing on it, return that face
if (
((BlockInQuestion == E_BLOCK_GLASS) ||
(BlockInQuestion == E_BLOCK_FENCE) ||
(BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) ||
(BlockInQuestion == E_BLOCK_COBBLESTONE_WALL)) &&
(Face == BLOCK_FACE_TOP)
)
if (CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face))
{
return Face;
}
else if (cBlockInfo::FullyOccupiesVoxel(BlockInQuestion) && (i != BLOCK_FACE_BOTTOM))
{
// Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face
return Face;
}
else
{
// Reset coords in preparation for next iteration
@@ -148,34 +154,16 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
eBlockFace Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true);
BLOCKTYPE BlockInQuestion;
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockInQuestion);
if (
(BlockInQuestion == E_BLOCK_GLASS) ||
(BlockInQuestion == E_BLOCK_STAINED_GLASS) ||
(BlockInQuestion == E_BLOCK_FENCE) ||
(BlockInQuestion == E_BLOCK_SOULSAND) ||
(BlockInQuestion == E_BLOCK_MOB_SPAWNER) ||
(BlockInQuestion == E_BLOCK_END_PORTAL_FRAME) || // Actual vanilla behaviour
(BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) ||
(BlockInQuestion == E_BLOCK_COBBLESTONE_WALL)
)
{
// Torches can be placed on tops of glass and fences, despite them being 'untorcheable'
// No need to check for upright orientation, it was done when the torch was placed
return true;
}
else if (!cBlockInfo::FullyOccupiesVoxel(BlockInQuestion))
BLOCKTYPE BlockInQuestion;
NIBBLETYPE BlockInQuestionMeta;
if (!a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockInQuestion, BlockInQuestionMeta))
{
return false;
}
else
{
return true;
}
return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face);
}
+6
View File
@@ -29,6 +29,12 @@ public:
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
if (m_BlockType == E_BLOCK_IRON_TRAPDOOR)
{
// Iron doors can only be toggled by redstone, not by right-clicking
return;
}
// Flip the ON bit on/off using the XOR bitwise operation
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x04);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
+26 -8
View File
@@ -23,10 +23,6 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
UNUSED(a_Player);
UNUSED(a_CursorX);
UNUSED(a_CursorY);
UNUSED(a_CursorZ);
// TODO: Disallow placement where the vine doesn't attach to something properly
BLOCKTYPE BlockType = 0;
NIBBLETYPE BlockMeta;
@@ -80,7 +76,21 @@ public:
/// Returns true if the specified block type is good for vines to attach to
static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
{
return ((a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType));
switch (a_BlockType)
{
case E_BLOCK_GLASS:
case E_BLOCK_STAINED_GLASS:
case E_BLOCK_CHEST:
case E_BLOCK_TRAPPED_CHEST:
{
// You can't attach a vine to this solid blocks.
return false;
}
default:
{
return cBlockInfo::IsSolid(a_BlockType);
}
}
}
@@ -138,7 +148,7 @@ public:
{
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, NULL, BlockX, a_RelY, BlockZ);
DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ);
}
a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0);
return;
@@ -166,23 +176,31 @@ public:
return false;
}
virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
{
UNUSED(a_ChunkInterface);
UNUSED(a_WorldInterface);
UNUSED(a_BlockPluginInterface);
// Vine cannot grow down if at the bottom:
if (a_RelY < 1)
{
return;
}
// Grow one block down, if possible:
BLOCKTYPE Block;
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
if (Block == E_BLOCK_AIR)
{
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY - 1, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, ssVineSpread))
if (!a_BlockPluginInterface.CallHookBlockSpread(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY - 1, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, ssVineSpread))
{
a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
}
}
}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right
+2 -2
View File
@@ -7,6 +7,6 @@ public:
virtual ~cBroadcastInterface() {}
virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
virtual void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
virtual void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = nullptr) = 0;
};
-1
View File
@@ -45,7 +45,6 @@ SET (HDRS
BlockGlowstone.h
BlockGravel.h
BlockHandler.h
BlockHayBale.h
BlockHopper.h
BlockIce.h
BlockLadder.h
+1 -1
View File
@@ -4,7 +4,7 @@
#include "ChunkInterface.h"
#include "ChunkMap.h"
#include "BlockHandler.h"
#include "WorldInterface.h"
#include "WorldInterface.h"