mojira.dev
MC-8345

Placing torch on backside of stairs impossible

The bug

You can't place torches or redstone torches on the backside of a stairs block. Not sure if this is a bug, but since the backside is the size of a normal block, it should probably be possible to place torches there.

Possible fix

A possible fix by @unknown can be found in this comment.

Related issues

Attachments

Comments

migrated
[media][media][media]
migrated

The stair block is considered transparent, so this is impossible. Minecraft is purposely simplified, and the game cannot differentiate based upon what side of the stairs the torch is placed.

migrated

But there's a torch at the top of the stair so it's not impossible...
The game can differentiate with some lines of code

migrated

Torches can be placed on the top of glass blocks, too. But not the sides.

migrated

But it's not impossible

bugi74

Indeed, not impossible. Attaching a screenshot done on a 1.4.7 client running with a fix for this issue.
Code for the fix comes as soon as I can test it a bit more (e.g. upside down stairs) and clean it up.

bugi74

(EDIT: Now this one removed in favor of the new screenshot with full functionality.)
Added the screenshot fixed-stairs-torches.png. Each torch was put in place in the normal way, and will not attach to any other surface of the stairs, only the backside.

P.S. it took about 2 hours from the idea to get to this point.

P.P.S. Embarrassingly enough, trying to do the same with upside down stairs caused a crash. 😛 ... 45 minutes later that and couple other bugs fixed, but one more issue left with trying to put torches on block immediately above or below another block with torch.

migrated

Forget this, I just want them to fix the ugly "horizontal line" that appears in the middle of right-side-up stairs caused by the texture orientation...

But anyway, you modded the game to fix this? Cool.

shufboyardee

Roadsguy, good news, they got rid of the ugly horizontal line, just this past snapshot or two.

migrated

Oh really? Great! 😃

Maybe I need to pay more attention. 😛

bugi74

(NOTE: would be best to fix all of this, MC-9176 and MC-2938 at the same time; see the MC-2938 for more text.)

Fix
The changes are somewhat long, and I didn't optimize them too much. Tested them quite a bit, but have left many block-torch combinations untested. Also, the changes only cover stair-blocks, not any other possible blocks with similar large surfaces. However, after these changes, adding the support for another block type is merely adding an override method in that block's class.

I added a method to Block, one that can be queried whether a given side of a block is a full solid surface (suitable for sticking thing on/at). The base method works (or at least is supposed to work) like before, only for full solid blocks or those who specifically declare that their top surface is ok (like glass). The BlockStairs has overridden that method to consider its orientation and specifically returns true for that backside (and the "bottom", whichever way it happens to be). The BlockTorch is then modified quite heavily to use this new method to resolve where or if a torch can be (or stay) attached to.

Code formatting style is "compact" for better readability in this comment.
(EDIT: Incorporated new versions from MC-9176.)

Block

/**
     * Override as necessary.
     * @param side 1 = bottom, 2 = z+1, 3 = z-1, 4 = x+1, 5 = x-1,  top = 0 or anything else
     * @return true if that side is solid and full surface
     */
    public boolean hasSolidFullSurfaceAt(IBlockAccess access, int x, int y, int z, int side) {
        switch (side) {
            case 1: return access.isBlockNormalCube(x, y, z);
            case 2:
            case 3:
            case 4:
            case 5: return access.isBlockNormalCube(x, y, z);
            default: return access.doesBlockHaveSolidTopSurface(x, y, z);
        }
    }

BlockStairs

public boolean hasSolidFullSurfaceAt(IBlockAccess access, int x, int y, int z, int side) {
        int metaData = access.getBlockMetadata(x, y, z);
        switch (side) {
            case 1: return (metaData & 4) == 0;
            case 2: return (metaData & 3) == 3;
            case 3: return (metaData & 3) == 2;
            case 4: return (metaData & 3) == 1;
            case 5: return (metaData & 3) == 0;
            default: return (metaData & 4) == 1; // true if it is upside down
        }
    }

And now the bulk... The method signatures were not changed, but the implementations are about 95% rewritten. Also, missing changes to method onBlockAdded(); didn't seem to affect manual placement, might be issue with generated structures in future, should they want to stick torches on backsides of stairs.

BlockTorch

private boolean canPlaceTorchOn(World world, int x, int y, int z) {
        // Check just the block/surface below
        return neighborHasSuitableSurfaceToBlockAt(world, x, y, z, 1);
    }

    public boolean canPlaceBlockAt(World world, int x, int y, int z) {
        // Go through neighbor blocks, using the new method for checking surfaces
        for (int i = 1; i <= 5; i++) {
            if (neighborHasSolidSurfaceToBlockAt(world, x, y, z, i))
                return true;
        }
        return false;
    }

    private boolean neighborHasSolidSurfaceToBlockAt(IBlockAccess access, int x, int y, int z, int side) {
        switch (side) {
            case 1: {
                y--;
                // Check for specials for block/surface below:
                int blockId = access.getBlockId(x, y, z);
                boolean b = blockId == Block.fence.blockID || blockId == Block.netherFence.blockID
                    || blockId == Block.glass.blockID || blockId == Block.cobblestoneWall.blockID;
                if (b)
                    return true;
                if (access.doesBlockHaveSolidTopSurface(x, y, z))
                    return true;
                break;
            }
            case 2: z++; if (access.isBlockNormalCube(x, y, z)) return true; break;
            case 3: z--; if (access.isBlockNormalCube(x, y, z)) return true; break;
            case 4: x++; if (access.isBlockNormalCube(x, y, z)) return true; break;
            case 5: x--; if (access.isBlockNormalCube(x, y, z)) return true; break;
            default: y++; break;
        }
        int blockId = access.getBlockId(x, y, z);
        Block block = Block.blocksList[blockId];
        if (block == null)
            return false;
        return block.hasSolidFullSurfaceAt(access, x, y, z, side);
    }

    public int onBlockPlaced(World world, int x, int y, int z, int side, float par6, float par7, float par8, int inputMetaData) {
        switch (side) {
            case 1: return neighborHasSolidSurfaceToBlockAt(world, x, y, z, side) ? 5 : inputMetaData;
            case 2: return neighborHasSolidSurfaceToBlockAt(world, x, y, z, side) ? 4 : inputMetaData;
            case 3: return neighborHasSolidSurfaceToBlockAt(world, x, y, z, side) ? 3 : inputMetaData;
            case 4: return neighborHasSolidSurfaceToBlockAt(world, x, y, z, side) ? 2 : inputMetaData;
            case 5: return neighborHasSolidSurfaceToBlockAt(world, x, y, z, side) ? 1 : inputMetaData;
            default: // Can not put it on ceiling.
                return inputMetaData;
        }
    }

    public void onNeighborBlockChange(World world, int x, int y, int z, int neighborBlockId) {
        if (this.dropTorchIfCantStay(world, x, y, z)) {
            // If here, the torch could stay on _some_ side of this block, but not necessarily on the one it used to be.
            int metaData = world.getBlockMetadata(x, y, z);
            boolean dropIt = false;
            switch (metaData) {
                case 1: dropIt = !neighborHasSolidSurfaceToBlockAt(world, x, y, z, 5); break;
                case 2: dropIt = !neighborHasSolidSurfaceToBlockAt(world, x, y, z, 4); break;
                case 3: dropIt = !neighborHasSolidSurfaceToBlockAt(world, x, y, z, 3); break;
                case 4: dropIt = !neighborHasSolidSurfaceToBlockAt(world, x, y, z, 2); break;
                case 5: dropIt = !neighborHasSolidSurfaceToBlockAt(world, x, y, z, 1); break;
                default: dropIt = true;
            }
            if (dropIt) {
                this.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0);
                world.setBlockWithNotify(x, y, z, 0);
            }
        }
    }

This cut&pasting from my changed sources may have missed a change or two, but the idea should be clear and easy to adapt/improve upon.

bugi74

Added a screenshot showing various cases of manually sticking torches on the backside of stairs.

kumasasa

Reopened.

migrated

Personally I can't see anything wrong with being able to place a torch on any side of a stair. Yes, if you're using the blocks /as stairs/ it would be unusual to put torches on them, but for any of a hundred different decorative permutations that could otherwise be possible with stairs, why not allow it?

I would actually make this argument for almost every block in the game; use minimal sanity checks for block placement and by and large let the player do what they want. If they don't like something because they think it's unrealistic, they won't do it. But if they come up with a creative use (such in the example of mushrooms being used as fake ropes, which is something I would never have thought of), why put barriers in their way?

bugi74

@Simon: I'd change your idea so that it is one more gamerule (accessed via commands), like '/gamerule unrestrictedBlockPlacement'. However, that is quite a large change (but not a difficult one); it not only needs to consider placing a thing on another block, but also all rules about keeping things in place. It is also a feature request, not a bugfix, so forums would be the right avenue for that.

bugi74

Updated the code fixes to be compatible with the fix for MC-9176.

bugi74

Affects 13w09b.

bugi74

Affects 13w09c.

migrated

Confirmed on 1.6.2.

Ezekiel

Is this still a concern in the latest Minecraft version 14w08a? If so, please update the affected versions in order to best aid Mojang ensuring bugs are still valid in the latest releases/pre-releases.

migrated

Still an issue in 08a and 1.7.5

migrated

Still an issue in 10c

migrated

Still present in 1.7.9.

migrated

Confirmed for 14w17a

migrated

Confirmed for 14w18a

migrated

Confirmed for 14w25b.

migrated

Confirmed for 14w26c

migrated

Confirmed for 14w34d

rydian

Confirmed in 1.8.1-pre1.

rydian
migrated

Confirmed for 15w46a

migrated

Confirmed for 15w51b

migrated

still in 16w44a

migrated

still in 1.11 Pre-Release 1

migrated

still in 1.11.2

migrated

migrated

Confirmed

Minecraft 1.4.6, Minecraft 1.4.7, Snapshot 13w04a, Snapshot 13w07a, Snapshot 13w09a, ..., Minecraft 16w44a, Minecraft 1.11 Pre-Release 1, Minecraft 1.11, Minecraft 1.11.2, Minecraft 17w06a

Minecraft 17w15a

Retrieved