Glass panes not correctly rendering with the back of stairs
When glass panes are placed they do not bind with the full block back of stairs like they should.
Linked Issues
is duplicated by4
Created Issue:
Glass panes not correctly rendering with the back of stairs
When glass panes are placed they do not bind with the full block back of stairs like they should.
Environment
Mac OSX 10.8.2 on Mac book pro 15" Early 2011 Java 1.6.0_37
relates to
relates to
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
relates to
Still happening in 1.9-pre2.
(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.)
/**
* 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);
}
}
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.
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.
Please provide a easier to understand screenshot (i.e. normal ground-up situation). Easier to test.
Also, closely related to MC-9176 and MC-8345 (both of them have code fixes provided). Should be easy to apply similar fix to this issue.
EDIT: MC-2938 is also closely related (and also have already code fixes provided). (Wish I was already at home, sounds like 15 minute fix.)
These fixes are in addition to the fixes above. Also, it would be best to fix all of this, MC-9176 and MC-8345 at the same time; the code changes are pretty much shared/similar. Also, once all fixes are imported, might be a good idea to take a look at the duplication and functionality over all, and give some much needed object-oriented love to the related code. Would reduce the amount of code, make coding new similar features a blink (instead of a pain of bugs), and thus reduce "maintenance costs".
Fixes
public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) { // boolean north = this.canConnectFenceTo(world, x, y, z - 1); // boolean south = this.canConnectFenceTo(world, x, y, z + 1); // boolean west = this.canConnectFenceTo(world, x - 1, y, z); // boolean east = this.canConnectFenceTo(world, x + 1, y, z); boolean north = this.canFenceAtConnectToDir(world, x, y, z, 3); boolean south = this.canFenceAtConnectToDir(world, x, y, z, 2); boolean west = this.canFenceAtConnectToDir(world, x, y, z, 5); boolean east = this.canFenceAtConnectToDir(world, x, y, z, 4); ... public void setBlockBoundsBasedOnState(IBlockAccess blockAccess, int x, int y, int z) { // boolean north = this.canConnectFenceTo(blockAccess, x, y, z - 1); // boolean south = this.canConnectFenceTo(blockAccess, x, y, z + 1); // boolean west = this.canConnectFenceTo(blockAccess, x - 1, y, z); // boolean east = this.canConnectFenceTo(blockAccess, x + 1, y, z); boolean north = this.canFenceAtConnectToDir(blockAccess, x, y, z, 3); boolean south = this.canFenceAtConnectToDir(blockAccess, x, y, z, 2); boolean west = this.canFenceAtConnectToDir(blockAccess, x, y, z, 5); boolean east = this.canFenceAtConnectToDir(blockAccess, x, y, z, 4); ... /** * @param dir 1 = bottom, 2 = z+1, 3 = z-1, 4 = x+1, 5 = x-1, top = 0 or anything else */ public boolean canFenceAtConnectToDir(IBlockAccess access, int x, int y, int z, int dir) { switch (dir) { case 2: { z++; break; } case 3: { z--; break; } case 4: { x++; break; } case 5: { x--; break; } default: return false; } if (this.canConnectFenceTo(access, x, y, z)) return true; // Old check int blockId = access.getBlockId(x, y, z); // Checking for full solid surface to touch.. Block block = Block.blocksList[blockId]; if (block == null) return false; return block.hasSolidFullSurfaceAt(access, x, y, z, dir); }
public void setBlockBoundsBasedOnState(IBlockAccess blockAccess, int x, int y, int z) { // boolean north = this.canConnectWallTo(blockAccess, x, y, z - 1); // boolean south = this.canConnectWallTo(blockAccess, x, y, z + 1); // boolean west = this.canConnectWallTo(blockAccess, x - 1, y, z); // boolean east = this.canConnectWallTo(blockAccess, x + 1, y, z); boolean north = this.canWallAtConnectToDir(blockAccess, x, y, z, 3); boolean south = this.canWallAtConnectToDir(blockAccess, x, y, z, 2); boolean west = this.canWallAtConnectToDir(blockAccess, x, y, z, 5); boolean east = this.canWallAtConnectToDir(blockAccess, x, y, z, 4); ... public boolean canWallAtConnectToDir(IBlockAccess access, int x, int y, int z, int dir) { switch (dir) { case 2: { z++; break; } case 3: { z--; break; } case 4: { x++; break; } case 5: { x--; break; } default: return false; } if (this.canConnectWallTo(access, x, y, z)) return true; // Old check int blockId = access.getBlockId(x, y, z); // Checking for full solid surface to touch.. Block block = Block.blocksList[blockId]; if (block == null) return false; return block.hasSolidFullSurfaceAt(access, x, y, z, dir); }
(Below, note the swapped order; halves the number of calls to the method.)
public boolean renderBlockFence(BlockFence blockFence, int x, int y, int z) { ... // if (blockFence.canConnectFenceTo(this.blockAccess, x - 1, y, z) || blockFence.canConnectFenceTo(this.blockAccess, x + 1, y, z)) { // var8 = true; // } // // if (blockFence.canConnectFenceTo(this.blockAccess, x, y, z - 1) || blockFence.canConnectFenceTo(this.blockAccess, x, y, z + 1)) { // var9 = true; // } // // boolean west = blockFence.canConnectFenceTo(this.blockAccess, x - 1, y, z); // boolean east = blockFence.canConnectFenceTo(this.blockAccess, x + 1, y, z); // boolean north = blockFence.canConnectFenceTo(this.blockAccess, x, y, z - 1); // boolean south = blockFence.canConnectFenceTo(this.blockAccess, x, y, z + 1); boolean west = blockFence.canFenceAtConnectToDir(blockAccess, x, y, z, 5); boolean east = blockFence.canFenceAtConnectToDir(blockAccess, x, y, z, 4); boolean north = blockFence.canFenceAtConnectToDir(blockAccess, x, y, z, 3); boolean south = blockFence.canFenceAtConnectToDir(blockAccess, x, y, z, 2); if (west || east) { var8 = true; } if (north || south) { var9 = true; } ... public boolean renderBlockWall(BlockWall blockWall, int x, int y, int z) { // boolean west = blockWall.canConnectWallTo(this.blockAccess, x - 1, y, z); // boolean east = blockWall.canConnectWallTo(this.blockAccess, x + 1, y, z); // boolean north = blockWall.canConnectWallTo(this.blockAccess, x, y, z - 1); // boolean south = blockWall.canConnectWallTo(this.blockAccess, x, y, z + 1); boolean west = blockWall.canWallAtConnectToDir(blockAccess, x, y, z, 5); boolean east = blockWall.canWallAtConnectToDir(blockAccess, x, y, z, 4); boolean north = blockWall.canWallAtConnectToDir(blockAccess, x, y, z, 3); boolean south = blockWall.canWallAtConnectToDir(blockAccess, x, y, z, 2); ...
Changes were tested against 1.4.7; the example screenshot 'fixed-backofstairs-fences.png' is from there (along with fixes applies to the two already mentioned other issues).
Related to MC-9176 and MC-2938.
With the fixes done on issues MC-9176 and MC-2938, this would not be difficult to change. It wouldn't look good without some additional changes (the upper horizontal bar seems to be too high).
Also, since the sign already has a vertical pole when attached as is, it makes me think whether attaching them to fence posts like that is intended. Though I can see the uses for it (and I've tried to do something like that myself).
Duplicate of MC-9176, please use the search function to see if your bug has already been submitted. Currently over 57% of tickets are being resolved as duplicate.
Would be nice if you can use the search engine next time.
Duplicate of MC-9176


Glass panes, fences and iron bars do not connect to stairs.
... because stairs are transparent.
The above is the explanation (=excuse) why they are not connected with the current code, but does not mean they are not intended to connect. See, for example,
MC-8345. The issue can be fixed to work as players would expect.(Seems I had already bookmarked this issue so I'd try fixing it, but haven't had yet time to get into it.)
Edit: I took a look at it, and using the changes from
MC-8345, this can be fixed somewhat easily. Unfortunately, easy doesn't equal to little work; certain change must be propagated through a bunch of classes, which means too much work for this night. Alternately, certain methods can be changed a tiny bit, but that would in turn require a lot of testing (to not break something else), or, a bunch of code could be copied and adapted to this specific case, but that is just bad coding style.Hmm.. looks like lots of the code to be copied in that last choice has already duplication in it, so it might actually give a decent result after some combining and cleanup. Have to have a better look at this... perhaps tomorrow.
I'm very much with MArkku here. And would those who use the excuse that stairs are transparent kindly explain why glass panes /do/ join to leaves, glass blocks and glowstone, all of which are classed as transparent blocks?
The reason why glass panes connect to the above blocks is that they are hard-coded to do so, the glass panes has been intentionally programmed to not connect to transparent blocks, and have a few exceptions (eg. if(par1IBlockAccess.isBlockSolid(par2 - 1, par3, par4) || par1IBlockAccess.getBlockId(par2 - 1, par3, par4) == Block.glass.blockId){ } this is just a simple example).
Exactly like fuj1n explains. And that is the part I'm going to "attack". I'll add similar smartness as in the torch placement bug. Just it wasn't as trivial to apply to this issue as to the other one, due to some design decisions/architecture hiccups. I'm still at work, but I'll get to this later today.
Sample screenshot 'fixed-panes-stairs.png' showing both torches attached and glass panes connected to backside of stair blocks. Code fixes incoming.
(NOTE: would be best to fix all of this,
MC-8345andMC-2938at the same time; see theMC-2938for more text.)Fix
The basic reason for the issue is the same as for the
MC-8345; the code does not have own method to check only surfaces of blocks, so it checks just the full block type, and also typically has some special case handling here and there (like fuj1n explained for this issue).To resolve the torches vs. backs of stairs, I added a method to check just for the block's surface (if it is a full and solid surface). It didn't directly work for this issue, as it was made just for the torch-stuff at the time. I made the necessary changes to accommodate both issues, and as a side-effect, made the new method work more correctly. (I'll update the code in the other issue, too.)
However, I also had to adjust certain method calls in a way that may have some undesired side-effects. Testing recommended.
Here are the code changes, using mix of MCP and my own namings:
/** * 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); } }I tested changes on 1.4.7, results as in the screenshot. (Though the torches need also the
MC-8345fixes applied, too.)Affects 13w09b.
Affects 13w09c.
Markku wrote a fix... why is this still unresolved?
I seriously hope this is not considered to be intended behavior. Voted.
I am seeing the same issue in the new 1.7.2 release.
Confirmed for 1.7.5, 14w08a and 14w10c
Confirmed for 14w11b
Confirmed in 1.8.1-pre1.
Confirmed in 1.8.1-pre5.
Still happening in 15w42a.
Still happening in 15w44b.
Still happening in 15w45a.
Still happening in 15w47a.
Still happening in 1.9-pre2.
Confirmed in 1.10.
still in 16w44a
still in 1.11 Pre-Release 1