Example #1
0
bool cItemHandler::OnPlayerPlace(
	cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
	int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
	int a_CursorX, int a_CursorY, int a_CursorZ
)
{
	if (a_BlockFace < 0)
	{
		// Clicked in air
		return false;
	}
	
	if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
	{
		// The clicked block is outside the world, ignore this call altogether (#128)
		return false;
	}
	
	BLOCKTYPE ClickedBlock;
	NIBBLETYPE ClickedBlockMeta;

	a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);

	// Check if the block ignores build collision (water, grass etc.):
	if (
		BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision() ||
		BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(&a_Player, ClickedBlockMeta)
	)
	{
		cChunkInterface ChunkInterface(a_World.GetChunkMap());
		BlockHandler(ClickedBlock)->OnDestroyedByPlayer(ChunkInterface, a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ);
	}
	else
	{
		AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
			
		if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
		{
			// The block is being placed outside the world, ignore this packet altogether (#128)
			return false;
		}
			
		NIBBLETYPE PlaceMeta;
		BLOCKTYPE PlaceBlock;
		a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);

		// Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
		// No need to do combinability (dblslab) checks, client will do that here.
		if (
			!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision() &&
			!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(&a_Player, PlaceMeta)
			)
		{
			// Tried to place a block into another?
			// Happens when you place a block aiming at side of block with a torch on it or stem beside it
			return false;
		}
	}

	// Get all the blocks to place:
	sSetBlockVector blocks;
	if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, blocks))
	{
		// Handler refused the placement, send that information back to the client:
		for (const auto & blk: blocks)
		{
			a_World.SendBlockTo(blk.GetX(), blk.GetY(), blk.GetZ(), &a_Player);
		}
		a_World.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, &a_Player);
		a_Player.GetInventory().SendEquippedSlot();
		return false;
	}
	
	// Try to place the blocks:
	if (!a_Player.PlaceBlocks(blocks))
	{
		// The placement failed, the blocks have already been re-sent, re-send inventory:
		a_Player.GetInventory().SendEquippedSlot();
		return false;
	}

	// Play the placement sound for the main block:
	for (const auto & blk: blocks)
	{
		// Find the main block by comparing the coords:
		if ((blk.GetX() != a_BlockX) || (blk.GetY() != a_BlockY) || (blk.GetZ() != a_BlockZ))
		{
			continue;
		}
		AString PlaceSound = cBlockInfo::GetPlaceSound(blk.m_BlockType);
		float Volume = 1.0f, Pitch = 0.8f;
		if (PlaceSound == "dig.metal")
		{
			Pitch = 1.2f;
			PlaceSound = "dig.stone";
		}
		else if (PlaceSound == "random.anvil_land")
		{
			Volume = 0.65f;
		}
		a_World.BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
		break;
	}  // for blk - blocks[]

	// Remove the "placed" item:
	if (a_Player.IsGameModeSurvival())
	{
		a_Player.GetInventory().RemoveOneEquippedItem();
	}
	return true;
}