Affects Version/s: Minecraft 1.8, Minecraft 1.8.1-pre2, Minecraft 1.8.1-pre3, Minecraft 1.8.1, Minecraft 1.8.3, Minecraft 1.8.4, Minecraft 1.8.8, Minecraft 15w31a, Minecraft 15w31b, Minecraft 15w31c, Minecraft 15w33b, Minecraft 15w33c, Minecraft 15w35e, Minecraft 15w36b, Minecraft 15w36c, Minecraft 15w36d, Minecraft 15w37a
Fix Version/s: Minecraft 15w38a
This post is about not correctly updated collision boxes of certain blocks.
It describes more than one issue but they are caused by the same problematic part of code and should be seen as one in order to decide on a good solution for them.
When it comes to explanation close to the code I will use MCP names. They should mostly speak for themselves.
As Searge just recently tweeted about it: I will try to keep the posted code to a minimum and give just the needed context for my fix (It's pretty much just the added code). I obviously don't intent to make any of the (especially with MCP) decompiled code public.
I will try to have a look on here in case there are any questions.
It causes the following wrong behaviors:
- Entities glitching into certain blocks randomly (e.g. into slabs)
- Pistons not pushing entities correctly (e.g. in elevators)
- Rendering issues (e.g. normal slab renders as upside down for a split second)
- Items/XPOrbs jumping up when on certain blocks (e.g. cauldron, stairs)
Fixing it will probably also break the following by the community used glitches:
- The most common wireless redstone
- test137e29's simple item elevator (This thing: Item elevator)
The item elevator is a default design used a lot by the technical community so it might be worth it to make it still work by design when the fix breaks it. I'll add a section about that at the very end of the post. Please consider it.
I will try to explain it on the example of into blocks glitching entities.
In Block.java we got 6 integer fields (minX, minY, minZ, maxX, maxY, maxZ).
The following method sets these values. It is overridden by all blocks that can have changeable collision boxes (e.g. slabs).
The usual way this is use is like that (let's imagine some method in Block.java):
Here we can already see the first risk this holds. It's not directly a bug but calls for creating bugs: What if you forget to call setBlockBoundsBasedOnState() before working with the values?
This case commonly happed. For example for chest, anvils and moving blocks. (These are just from experience, I didn't look it up. So forgive me if I'm mistaken )
See the ways to reproduce section for more detailed examples.
This is also what's used to create wireless redstone.
While this is not really a bug I guess it's still not what you want. Especially when it comes to the plugin API. The system works for blocks with simple AABBs. But by now Minecraft is not limited to that.
The second issue is less visible but you might guess it when I bring up that by now in Minecraft SSP two threads run. One acting as a client and one as a local server.
Both of these threads have access to Block.java. Both work with it.
A common case is that the client thread uses setBlockBoundsBasedOnState() to set the block bounds for the renderer.
An other common case is that the server thread uses it in order to calculate entity collisions.
If both of these happen at the same time the values are changed by the other thread and therefor can cause entities to glitch into blocks or the renderer to show wrong things.
In the long run it should be completely gotten rid of the setBlockBoundsBasedOnState() and the 6 integer values in Block.java. This design just doesn't work well with multi threading and making all code that uses the on top described pattern synchronized is not really an option.
This needs a lot of refactoring and therefor takes a lot of time though.
I limited myself to explain my idea how to fix the collision issues with entities glitching into blocks.
First up I added a few methods for convenience here and there:
Now the following method should be overridden for all affected blocks that have a simple AABB (with that I mean that they don't need several AABBs).
For example that would be slabs, chests and anvils.
It should be overridden to work independent from setBlockBoundsBasedOnState() and the 6 integer values in Block.java.
For slabs you can nicely add the possible AABBs to the property enum.
For blocks which can need more than one AABB we want to override this method:
It's for example called when the collision check of an entity is done to build a list of blocks which might collide with it.
The implementation in Block.java just calls getCollisionBoundingBox() and adds this AABB to the list. That's why we can override getCollisionBoundingBox() for simple blocks.
But I want to show the example of a fence too. For fences I added a few static fields which contain all possibly needed AABBs.
For other blocks like stairs or moving blocks it might get more complicated but as the functionality is already in there, it just needs to be refactored a bit.
In order to fix all issues with it (for example bouncing items would still happen in some cases) and to completely get rid of the setBlockBoundsBasedOnState() obviously more work is required.
Reproducing the first issue is quite easy:
1. Place a double chest.
2. Walk against it from the smaller side. Keep walking against it in the next steps.
3. Look first at the chest closer to you and then at the one further away (by looking at it you update the values in Block.java).
4. You should notice that you move forward and get set back all the time.
Same works even better with anvils:
1. Place two anvils in a row. One facing north-south, the other one east-west.
2. Walk against one of them. And keep walking in the next steps.
3. Look at one then at the other and then at the first anvil again.
4. You should walk through it now.
A good way to reproduce the entities glitching into blocks (threading issue) is the following:
1. Create a new superflat world with the following string: “3;minecraft:bedrock,20*minecraft:stone_slab;1;” (You can use other affected blocks than slabs.)
2. Place a upside down slab somewhere in the world.
3. Place a armor stand (or an other entity) on top of it. (For fences you want to have a water stream pushing a mob against it.)
4. Now set the render distance to a low and then to a high value again (This is to make it more likely by as it causes updates on the blocks).
5. You should be able to see two things. First up if you look at the upside down slab it's hitbox will constantly change to a normal slab and back. Secondly the armor stand falls through the slab.
Pistons not pushing entities:
1. Build up whats shown in this screenshot.
2. Stand where I stand in the screenshot and look at the sideways piston.
3. Place a torch where I look at in the screenshot.
4. You will find that you don't the pushed up. If you make the sideways facing piston look up you will get pushed up.
The rendering issues rarely happen. You can force them by having a lot of the affected blocks around. But as they are a less important issue and somewhat hard to reproduce I will just leave it at that.
Items jumping up is easy to reproduce again:
1. Place a stair
2. Throw an item into the cut out part.
3. It jumps away.
Same with cauldrons and other affected blocks. The item elevator linked earlier is also powered by this issue / a way to reproduce it.
It's likely that MC-2025 and/or some duplicates of it describe mobs glitching through fences. It's not unlikely that it is due to this bug.
Also in the duplicates of
MC-10 are a few posts were mobs really glitch through fences (which is likely this issue).
There is probably more issues connected to it but I spent enough time browsing the bugtracker for now.
If one of the bad-cop-mods feels like linking the issues to this one that would be great
If the partial fix I showed is used (or something similar) then the simple item elevator can be fixed by adding setBlockBoundsBasedOnState() to the method which makes items fly out of blocks in the right spot.
In case you completely get rid of the old system now or some time in future please still consider to leave the fence item elevators working by adding a few lines in this method.
I would be killed by the technical community if I didn't at least try to make you keep the item elevators
This issue pretty much affects all blocks which have a changeable collision box or a collision box which consists out of more than one bounding box.
This list is probably not complete but I'll give my best. Also the effect of this issue might not show the same for all of them.
The following blocks are probably affected by this glitch in some way:
Snow layers, cobble wall, mossy cobble wall, ladders, iron bars, glass panes, heads, stairs, slabs, hopper, wooden trapdoors, iron trapdoors, all doors, cactus, anvils, chests, trapped chests, brewing stand, all fences, all fence gates, extended pistons, extending pistons, end portal frames, cake and cauldrons.
Wow, that got long.
In short: For each block just one global Bounding Box is saved in 6 integer values. They have to be set dependent on the state of a block in a certain position before anything is done with them.
This calls for coding bugs and causes threading issues.
I will also make a video explaining the basics. It might take a week till I find time for it though. <Link will follow>
Thanks for reading. Forgive me all the typos, it's late