-
Bug
-
Resolution: Fixed
-
Minecraft 1.6.2, Minecraft 1.6.4, Minecraft 13w41b, Minecraft 1.7.1, Minecraft 1.7.2, Minecraft 13w48b, Minecraft 1.7.9, Minecraft 14w17a, Minecraft 14w21b, Minecraft 14w30c, Minecraft 14w34d, Minecraft 1.8-pre3, Minecraft 1.8, Minecraft 1.9, Minecraft 1.10.2, Minecraft 16w43a, Minecraft 16w44a, Minecraft 1.11 Pre-Release 1, Minecraft 1.11, Minecraft 16w50a, Minecraft 1.11.1, Minecraft 1.11.2, Minecraft 17w06a, Minecraft 17w13a, Minecraft 17w13b, Minecraft 17w14a, Minecraft 17w15a, Minecraft 17w16a, Minecraft 17w17b, Minecraft 17w18a, Minecraft 17w18b, Minecraft 1.12 Pre-Release 1, Minecraft 1.12 Pre-Release 2, Minecraft 1.12 Pre-Release 3, Minecraft 1.12 Pre-Release 5, Minecraft 1.12 Pre-Release 6, Minecraft 1.12 Pre-Release 7, Minecraft 1.12, Minecraft 1.12.1 Pre-Release 1, Minecraft 1.12.1, Minecraft 1.12.2 Pre-Release 1, Minecraft 1.12.2 Pre-Release 2, Minecraft 1.12.2
-
OS: Mac OS X (ver 10.8.4, arch x86_64)
Java: 1.6.0_51 (by Apple Inc.)
Launcher: 1.2.3 (bootstrap 4)
-
Confirmed
-
Survival
If you press an inventory manipulation key (Q or a number key from 1 to 9) while in an inventory and hovering over certain items in your inventory at the same time as you press a key to close the inventory (E or esc), the game crashes.
Info by pokechu22.
To reproduce
- Make a double chest
- Open the chest
- Put an item in the slot that your cursor defaults to in the chest (the middle slot on the bottom row)
- Press both 1 and E at the exact same time.
- If the game did not crash, reopen the chest and try again (the benefit of using that slot is that you don't need to move the mouse and thus can try repeatedly quickly; the item can be either in hotbar slot 1 or the chest slot for the game to crash)
Speculations on the cause
I think this specific part of the crash report explains what's happening pretty well:
-- Affected screen -- Details: Screen name: ~~ERROR~~ NullPointerException: null
Note also the message of the exception:
java.lang.IndexOutOfBoundsException: Index: 53, Size: 46
Specifically, size 46. What inventory has 46 slots? Answer: the player inventory! (numbered 0 to 45).
It seems like it's trying to swap items using indexes from the old inventory within the player's inventory. This can further be seen by the positions where it crashes...
Which slots cause crashes, exactly?
A curious property of this bug is it never happens in some inventories (such as furnaces and enchantment tables), and never happens in the first slots of any inventory.
Well, assuming that it is the case of the wrong inventory being used, a quick look at the wiki.vg article on inventories should show what slots have indexes greater than 45 in different inventories, and thus would be capable of causing crashes. There's only a few: chests (of all sizes where there's more than 1 row), chested donkeys and mules, shulker boxes, and llamas with a strength of at least 4. In all of those inventories, it can be reproduced in the 9th slot of the hotbar, and in the case of large chests can be reproduced in all of the player's inventory slots and the last 8 items of the last chest row.
If this were 1.8 (before the introduction of the offhand slot), the largest player slot would be 44 instead of 45, you'd also be able to reproduce this in crafting tables with the 9th hotbar slot, and in some more slots in other inventories.
Code analysis
All of this is based off of MCP for 1.10.
Adding a debug logging println into GuiContainer.keyTyped (which handles slot manipulation and inventory closing) like this can show some useful information:
protected void keyTyped(char typedChar, int keyCode) throws IOException { System.out.println("Key '" + typedChar + "' typed in " + this + " - active is " + this.mc.currentScreen + " (same = " + (this.mc.currentScreen == this) + ")"); // Regular code... if (keyCode == 1 || keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode()) { this.mc.thePlayer.closeScreen(); } this.checkHotbarKeys(keyCode); if (this.theSlot != null && this.theSlot.getHasStack()) { if (keyCode == this.mc.gameSettings.keyBindPickBlock.getKeyCode()) { this.handleMouseClick(this.theSlot, this.theSlot.slotNumber, 0, ClickType.CLONE); } else if (keyCode == this.mc.gameSettings.keyBindDrop.getKeyCode()) { this.handleMouseClick(this.theSlot, this.theSlot.slotNumber, isCtrlKeyDown() ? 1 : 0, ClickType.THROW); } } }
Normally (when the '1' is processed before the 'e', you'd get this:
Key '1' typed in net.minecraft.client.gui.inventory.GuiChest@77f36fa7 - active is net.minecraft.client.gui.inventory.GuiChest@77f36fa7 (same = true) Key 'e' typed in net.minecraft.client.gui.inventory.GuiChest@77f36fa7 - active is net.minecraft.client.gui.inventory.GuiChest@77f36fa7 (same = true)
But when the game crashes, you get this:
Key 'e' typed in net.minecraft.client.gui.inventory.GuiChest@685af84b - active is net.minecraft.client.gui.inventory.GuiChest@685af84b (same = true) Key '1' typed in net.minecraft.client.gui.inventory.GuiChest@685af84b - active is null (same = false)
It's running the move item action on the wrong screen, as predicted! But why is the closed screen still getting keyboard input?
Well, for whatever reason GuiScreen processes its own keyboard input:
/** * Delegates mouse and keyboard input. */ public void handleInput() throws IOException { if (Mouse.isCreated()) { while (Mouse.next()) { this.handleMouseInput(); } } if (Keyboard.isCreated()) { while (Keyboard.next()) { this.handleKeyboardInput(); } } } // Snip - don't need to include handleMouseInput... /** * Handles keyboard input. */ public void handleKeyboardInput() throws IOException { char c0 = Keyboard.getEventCharacter(); if (Keyboard.getEventKey() == 0 && c0 >= 32 || Keyboard.getEventKeyState()) { this.keyTyped(c0, Keyboard.getEventKey()); } this.mc.dispatchKeypresses(); }
handleInput continues running on the screen it started on, even if that screen is closed! Thus, the items are swapped when 1 is pressed, even if the screen is closed. That item swapping causes a crash, because the number of available items is smaller on the player inventory than the previous one.
The "ugly hack" fix for this would be to change handleInput to bail out early if the screen changed:
public void handleInput() throws IOException { if (Mouse.isCreated()) { while (Mouse.next()) { if (this != this.mc.currentScreen) { // Screen changed - bail out! return; } this.handleMouseInput(); } } if (Keyboard.isCreated()) { while (Keyboard.next()) { if (this != this.mc.currentScreen) { // Screen changed - bail out! return; } this.handleKeyboardInput(); } } }
A better fix would be to remove handleInput entirely and just call handleMouseInput / handleKeyboardInput from within the same place that normal input is handled instead of having two input handling loops.
- is duplicated by
-
MC-30033 Hopper: java.lang.IndexOutOfBoundsException: Index: 58, Size: 45
- Resolved
-
MC-30122 Hopper: java.lang.IndexOutOfBoundsException: Index: 49, Size: 45
- Resolved
-
MC-30152 Hopper: java.lang.IndexOutOfBoundsException: Index: 48, Size: 45
- Resolved
-
MC-30328 Hopper: java.lang.IndexOutOfBoundsException: Index: 49, Size: 45
- Resolved
-
MC-31289 Hopper: java.lang.IndexOutOfBoundsException: Index: 54, Size: 45
- Resolved
-
MC-31705 Hopper: java.lang.IndexOutOfBoundsException: Index: 60, Size: 45
- Resolved
-
MC-31949 Hopper: java.lang.IndexOutOfBoundsException: Index: 46, Size: 45
- Resolved
-
MC-31961 Hopper: java.lang.IndexOutOfBoundsException: Index: 87, Size: 45
- Resolved
-
MC-32003 Hopper: java.lang.IndexOutOfBoundsException: Index: 60, Size: 45
- Resolved
-
MC-32020 Hopper: java.lang.IndexOutOfBoundsException: Index: 81, Size: 45
- Resolved
-
MC-32070 Hopper: java.lang.IndexOutOfBoundsException: Index: 58, Size: 45
- Resolved
-
MC-32667 Hopper: java.lang.IndexOutOfBoundsException: Index: 49, Size: 45
- Resolved
-
MC-32904 Hopper: java.lang.IndexOutOfBoundsException: Index: 51, Size: 45
- Resolved
-
MC-33130 Hopper: java.lang.IndexOutOfBoundsException: Index: 64, Size: 45
- Resolved
-
MC-35052 Hopper: java.lang.IndexOutOfBoundsException: Index: 53, Size: 45
- Resolved
-
MC-35212 Hopper: java.lang.IndexOutOfBoundsException: Index: 49, Size: 45
- Resolved
-
MC-35367 Hopper: java.lang.IndexOutOfBoundsException: Index: 53, Size: 45
- Resolved
-
MC-36221 Hopper: java.lang.IndexOutOfBoundsException: Index: 66, Size: 45
- Resolved
-
MC-36231 Hopper: java.lang.IndexOutOfBoundsException: Index: 55, Size: 45
- Resolved
-
MC-37190 Hopper: java.lang.IndexOutOfBoundsException: Index: 54, Size: 45
- Resolved
-
MC-37424 Hopper: java.lang.IndexOutOfBoundsException: Index: 81, Size: 45
- Resolved
-
MC-37442 Hopper: java.lang.IndexOutOfBoundsException: Index: 54, Size: 45
- Resolved
-
MC-37559 Hopper: java.lang.IndexOutOfBoundsException: Index: 84, Size: 45
- Resolved
-
MC-37621 Hopper: java.lang.IndexOutOfBoundsException: Index: 60, Size: 45
- Resolved
-
MC-37711 Hopper: java.lang.IndexOutOfBoundsException: Index: 49, Size: 45
- Resolved
-
MC-37725 Hopper: java.lang.IndexOutOfBoundsException: Index: 87, Size: 45
- Resolved
-
MC-37879 Hopper: java.lang.IndexOutOfBoundsException: Index: 50, Size: 45
- Resolved
-
MC-41258 game crash
- Resolved
-
MC-41524 Hopper: java.lang.IndexOutOfBoundsException: Index: 85, Size: 45
- Resolved
-
MC-43294 SMP - IndexOutOfBoundsException (Index: 48, Size: 45)
- Resolved
-
MC-43458 Game is closed
- Resolved
-
MC-43762 Updating screen events
- Resolved
-
MC-54639 Updating screen events
- Resolved
-
MC-54685 Minecraft crashed on closing a chest with E and accidentally pressing 2
- Resolved
-
MC-56223 In a chest, holding ESC+1 while highlighting any hotbar slot crashes game
- Resolved
-
MC-63851 Game crashed while using hotkeys to craft a new pick.
- Resolved
-
MC-91455 Hopper: java.lang.IndexOutOfBoundsException: Index: 55, Size: 45
- Resolved
-
MC-106400 Crash when closing a chest
- Resolved
-
MC-112854 Windows 10 resource starvation kills game engine with NULL pointer reference
- Resolved
-
MC-116688 Inventory crash the game
- Resolved
- relates to
-
MC-64947 Opening inventory takes precedence over typing a command or chatting
- Reopened
-
MC-3619 Game randomly crash, when working with items inside chest
- Resolved