[Mod] Pokechu22
- pokechu22
- pokechu22
- America/Los_Angeles
- Yes
- No
A crash with a instant redstone not gate. The not gate is vanilla and logical, but it now crashes.
A crash with a instant redstone not gate. The not gate is vanilla and logical, but it now crashes. This happens in 13w04a+, not sure about before.
Windows 8 full and java 7, but seems non-specic.
This is my first bug-report, I hope that there is a place for screenshots somewhere.
Can be seen with this super flat seed: 2;7,89,53x0,33:6,199x0,20;2;village
Can be seen with this super flat seed: 2;7,89,53x0,33:6,199x0,20;2;village
Can be seen with this super flat seed: 2;7,89,53x0,33:6,199x0,20;2;village
Ocours with pistions and stickypistons with data values of 6 or 7.
Can be seen with this super flat seed: 2;7,89,53x0,33:6,199x0,20;2;village
Ocours with pistions and stickypistons with data values of 6 or 7.
Crashes on rising edge of power.
Occurs on super flat maps made of beds, or vines. Vines on block update, Beds on removal (Tries to remove the one in front indefinitely)
Pistons in this setup cause graphical glitches. Made of quartz, for one frame, one quartz becomes bricks. Also, a the bottom piston in the back turns transparent on the head for a frame. I cant get a screenshot because my computer is too fast for me to capture a frame
Pistons in this setup cause graphical glitches. Made of quartz, for one frame, one quartz becomes bricks. Also, a the bottom piston in the back turns transparent on the head for a frame. I cant get a screenshot because my computer is too fast for me to capture a frame
![]()
The design is a double extender by codecrafted.
(Im getting the link)
Pistons in this setup cause graphical glitches. Made of quartz, for one frame, one quartz becomes bricks. Also, a the bottom piston in the back turns transparent on the head for a frame. I cant get a screenshot because my computer is too fast for me to capture a frame
![]()
The design is a double extender by codecrafted.
(Im getting the link)Pistons in this setup cause graphical glitches. Made of quartz, for one frame, one quartz becomes bricks. Also, a the bottom piston in the back turns transparent on the head for a frame. I cant get a screenshot because my computer is too fast for me to capture a frame
![]()
The design is a double extender by codecrafted.
http://www.youtube.com/watch?v=IP3Em1lcbrI
Ocasionaly when Minecraft is starting,
Ocasionaly when Minecraft is starting,
Ocasionaly when Minecraft is launched, OpenAL fails to start and there is no sound. Generally it works fine, but with a less than 10% chance, it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:
{{
asdf
27 achievements
210 recipes
Setting user: pokechu22, 8172470959570797165
LWJGL Version: 2.4.2Starting up SoundSystem...
Initializing LWJGL OpenAL
(The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.or
g)
Error in class 'LibraryLWJGLOpenAL'
Unable to initialize OpenAL. Probable cause: OpenAL not supported.
ERROR MESSAGE:
Could not locate OpenAL library.
STACK TRACE:
org.lwjgl.openal.AL.create(AL.java:153)
org.lwjgl.openal.AL.create(AL.java:104)
org.lwjgl.openal.AL.create(AL.java:191)
paulscode.sound.libraries.LibraryLWJGLOpenAL.init(SourceFile:164)
paulscode.sound.SoundSystem.CommandNewLibrary(SourceFile:1576)
paulscode.sound.SoundSystem.CommandQueue(SourceFile:2572)
paulscode.sound.CommandThread.run(SourceFile:121)
ERROR MESSAGE:
Could not locate OpenAL library.Starting up SoundSystem...
Switching to No Sound
(Silent Mode)}}
Ocasionaly when Minecraft is launched, OpenAL fails to start and there is no sound. Generally it works fine, but with a less than 10% chance, it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:
{{
asdf
27 achievements
210 recipes
Setting user: pokechu22, 8172470959570797165
LWJGL Version: 2.4.2Starting up SoundSystem...
Initializing LWJGL OpenAL
(The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.or
g)
Error in class 'LibraryLWJGLOpenAL'
Unable to initialize OpenAL. Probable cause: OpenAL not supported.
ERROR MESSAGE:
Could not locate OpenAL library.
STACK TRACE:
org.lwjgl.openal.AL.create(AL.java:153)
org.lwjgl.openal.AL.create(AL.java:104)
org.lwjgl.openal.AL.create(AL.java:191)
paulscode.sound.libraries.LibraryLWJGLOpenAL.init(SourceFile:164)
paulscode.sound.SoundSystem.CommandNewLibrary(SourceFile:1576)
paulscode.sound.SoundSystem.CommandQueue(SourceFile:2572)
paulscode.sound.CommandThread.run(SourceFile:121)
ERROR MESSAGE:
Could not locate OpenAL library.Starting up SoundSystem...
Switching to No Sound
(Silent Mode)}}
Ocasionaly when Minecraft is launched, OpenAL fails to start and there is no sound. Generally it works fine, but with a less than 10% chance, it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:asdf 27 achievements 210 recipes Setting user: pokechu22, 8172470959570797165 LWJGL Version: 2.4.2 Starting up SoundSystem... Initializing LWJGL OpenAL (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.or g) Error in class 'LibraryLWJGLOpenAL' Unable to initialize OpenAL. Probable cause: OpenAL not supported. ERROR MESSAGE: Could not locate OpenAL library. STACK TRACE: org.lwjgl.openal.AL.create(AL.java:153) org.lwjgl.openal.AL.create(AL.java:104) org.lwjgl.openal.AL.create(AL.java:191) paulscode.sound.libraries.LibraryLWJGLOpenAL.init(SourceFile:164) paulscode.sound.SoundSystem.CommandNewLibrary(SourceFile:1576) paulscode.sound.SoundSystem.CommandQueue(SourceFile:2572) paulscode.sound.CommandThread.run(SourceFile:121) ERROR MESSAGE: Could not locate OpenAL library. Starting up SoundSystem... Switching to No Sound (Silent Mode)I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode.
Ocasionaly when Minecraft is launched, OpenAL fails to start and there is no sound. Generally it works fine, but
with a less than 10% chance,it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:asdf 27 achievements 210 recipes Setting user: pokechu22, 8172470959570797165 LWJGL Version: 2.4.2 Starting up SoundSystem... Initializing LWJGL OpenAL (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.or g) Error in class 'LibraryLWJGLOpenAL' Unable to initialize OpenAL. Probable cause: OpenAL not supported. ERROR MESSAGE: Could not locate OpenAL library. STACK TRACE: org.lwjgl.openal.AL.create(AL.java:153) org.lwjgl.openal.AL.create(AL.java:104) org.lwjgl.openal.AL.create(AL.java:191) paulscode.sound.libraries.LibraryLWJGLOpenAL.init(SourceFile:164) paulscode.sound.SoundSystem.CommandNewLibrary(SourceFile:1576) paulscode.sound.SoundSystem.CommandQueue(SourceFile:2572) paulscode.sound.CommandThread.run(SourceFile:121) ERROR MESSAGE: Could not locate OpenAL library. Starting up SoundSystem... Switching to No Sound (Silent Mode)I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode.
Ocasionaly when Minecraft is launched, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode.
Experienced on
windows 7, 8, and 10; Java 6, 7, and 8; seems to be non-specific.Experienced on Windows Vista, 7, 8, and 10; Java 6, 7, and 8; seems to be non-specific.
Ocasionaly when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.comNote that I brute-forced this reproduction with a script; unfortunately that script wasn't smart enough to handle standard error output, so the actual MMDevApiOpenPlayback: Device init failed messages aren't included but still likely happened. Also, the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Also, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist - the "Could not load OpenAL library" message from it probably is a red herring; the earlier Could not open ALC device is probably more useful.
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.comNote that
I brute-forced this reproduction with a script; unfortunately that script wasn't smart enough to handle standard error output, so the actualMMDevApiOpenPlayback: Device init failedmessages aren't included but still likely happened. Also, the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Also, note thatC:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist - the "Could not load OpenAL library" message from it probably is a red herring; the earlier Could not open ALC device is probably more useful.I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com Could not locate symbol glEnableClientStateiEXT Could not locate symbol glDisableClientStateiEXT Could not locate symbol glGetFloati_vEXT Could not locate symbol glGetDoublei_vEXT Could not locate symbol glGetPointeri_vEXTNote that the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Additionally, "Could not locate symbol" at the bottom also occurs each time. Finally, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist - the "Could not load OpenAL library" message from it probably is a red herring; the earlier Could not open ALC device and "MMDevApiOpenPlayback: Device init failed: 0x80004005" are probably more useful.
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com Could not locate symbol glEnableClientStateiEXT Could not locate symbol glDisableClientStateiEXT Could not locate symbol glGetFloati_vEXT Could not locate symbol glGetDoublei_vEXT Could not locate symbol glGetPointeri_vEXTNote that the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Additionally, "Could not locate symbol" at the bottom also occurs each time. Finally, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist - the "Could not load OpenAL library" message from it probably is a red herring; the earlier Could not open ALC device and "MMDevApiOpenPlayback: Device init failed: 0x80004005" are probably more useful.
On further inspection, here's the code that generates that error. Note that 0x80004005 is a completely useless error code; it just represents E_FAIL which means "Unspecified failure". It seems that the OpenAL code doesn't even make more specific errors, but I don't know enough of the Windows API (or C in general) to understand it.
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args,
gives this:[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64[21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String)[21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC deviceAL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005[21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC deviceAL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005[21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com Could not locate symbol glEnableClientStateiEXT Could not locate symbol glDisableClientStateiEXT Could not locate symbol glGetFloati_vEXT Could not locate symbol glGetDoublei_vEXT Could not locate symbol glGetPointeri_vEXTNote that the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Additionally, "Could not locate symbol" at the bottom also occurs each time. Finally, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist - the "Could not load OpenAL library" message from it probably is a red herring; the earlier Could not open ALC device and "MMDevApiOpenPlayback: Device init failed: 0x80004005" are probably more useful.
On further inspection, here's the code that generates that error. Note that 0x80004005 is a completely useless error code; it just represents E_FAIL which means "Unspecified failure". It seems that the OpenAL code doesn't even make more specific errors, but I don't know enough of the Windows API (or C in general) to understand it.
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, and with the system environment variable ALSOFT_LOGLEVEL set to 3, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 AL lib: (II) alc_initconfig: Supported backends: mmdevapi, dsound, winmm, null, wave AL lib: (II) GetConfigValue: Key general:disable-cpu-exts not found AL lib: (II) FillCPUCaps: Got caps: SSE AL lib: (II) GetConfigValue: Key general:rt-prio not found AL lib: (II) GetConfigValue: Key general:resampler not found AL lib: (II) GetConfigValue: Key general:trap-al-error not found AL lib: (II) GetConfigValue: Key general:trap-alc-error not found AL lib: (II) GetConfigValue: Key reverb:boost not found AL lib: (II) GetConfigValue: Key reverb:emulate-eax not found AL lib: (II) GetConfigValue: Key general:drivers not found [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) AL lib: (II) MMDevApiMsgProc: Starting message thread AL lib: (II) alc_initconfig: Initialized backend "mmdevapi" AL lib: (II) alc_initconfig: Added "mmdevapi" for playback AL lib: (II) alc_initconfig: Initialized backend "dsound" AL lib: (II) alc_initconfig: Added "dsound" for capture AL lib: (II) GetConfigValue: Key general:excludefx not found AL lib: (II) GetConfigValue: Key general:default-reverb not found AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) MMDevApiMsgProc: Starting message loop [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com Could not locate symbol glEnableClientStateiEXT Could not locate symbol glDisableClientStateiEXT Could not locate symbol glGetFloati_vEXT Could not locate symbol glGetDoublei_vEXT Could not locate symbol glGetPointeri_vEXTNote that the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Additionally, "Could not locate symbol" at the bottom also occurs each time. Finally, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist - the "Could not load OpenAL library" message from it probably is a red herring; the earlier Could not open ALC device and "MMDevApiOpenPlayback: Device init failed: 0x80004005" are probably more useful.
On further inspection, here's the code that generates that error. Note that 0x80004005 is a completely useless error code; it just represents E_FAIL which means "Unspecified failure".
A successful OpenAL startup on my machine looks like this, for reference:
AL lib: (II) alc_initconfig: Supported backends: mmdevapi, dsound, winmm, null, wave AL lib: (II) GetConfigValue: Key general:disable-cpu-exts not found AL lib: (II) FillCPUCaps: Got caps: SSE AL lib: (II) GetConfigValue: Key general:rt-prio not found AL lib: (II) GetConfigValue: Key general:resampler not found AL lib: (II) GetConfigValue: Key general:trap-al-error not found AL lib: (II) GetConfigValue: Key general:trap-alc-error not found AL lib: (II) GetConfigValue: Key reverb:boost not found AL lib: (II) GetConfigValue: Key reverb:emulate-eax not found AL lib: (II) GetConfigValue: Key general:drivers not found AL lib: (II) MMDevApiMsgProc: Starting message thread AL lib: (II) MMDevApiMsgProc: Starting message loop AL lib: (II) alc_initconfig: Initialized backend "mmdevapi" AL lib: (II) alc_initconfig: Added "mmdevapi" for playback AL lib: (II) alc_initconfig: Initialized backend "dsound" AL lib: (II) alc_initconfig: Added "dsound" for capture AL lib: (II) GetConfigValue: Key general:excludefx not found AL lib: (II) GetConfigValue: Key general:default-reverb not found AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (II) MMDevApiMsgProc: Got message 1024 AL lib: (II) alcOpenDevice: Created device 0000000025070090, "Speakers (High Definition Audio Device)" AL lib: (II) UpdateDeviceParams: Pre-reset: Stereo, Float, 44100hz, 1024 update size x4 AL lib: (II) MMDevApiMsgProc: Got message 1025 AL lib: (II) UpdateDeviceParams: Post-reset: Stereo, Float, 44100hz, 896 update size x4 AL lib: (II) GetConfigValue: Key general:layout_stereo not found AL lib: (II) GetConfigValue: Key general:layout not found AL lib: (II) GetConfigValue: Key general:hrtf not found AL lib: (II) UpdateDeviceParams: HRTF disabled AL lib: (II) UpdateDeviceParams: BS2B disabled AL lib: (II) GetConfigValue: Key general:wide-stereo not found AL lib: (II) MMDevApiMsgProc: Got message 1026 AL lib: (II) alcCreateContext: Created context 0000000025088450
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, and with the system environment variable ALSOFT_LOGLEVEL set to 3, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 AL lib: (II) alc_initconfig: Supported backends: mmdevapi, dsound, winmm, null, wave AL lib: (II) GetConfigValue: Key general:disable-cpu-exts not found AL lib: (II) FillCPUCaps: Got caps: SSE AL lib: (II) GetConfigValue: Key general:rt-prio not found AL lib: (II) GetConfigValue: Key general:resampler not found AL lib: (II) GetConfigValue: Key general:trap-al-error not found AL lib: (II) GetConfigValue: Key general:trap-alc-error not found AL lib: (II) GetConfigValue: Key reverb:boost not found AL lib: (II) GetConfigValue: Key reverb:emulate-eax not found AL lib: (II) GetConfigValue: Key general:drivers not found [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) AL lib: (II) MMDevApiMsgProc: Starting message thread AL lib: (II) alc_initconfig: Initialized backend "mmdevapi" AL lib: (II) alc_initconfig: Added "mmdevapi" for playback AL lib: (II) alc_initconfig: Initialized backend "dsound" AL lib: (II) alc_initconfig: Added "dsound" for capture AL lib: (II) GetConfigValue: Key general:excludefx not found AL lib: (II) GetConfigValue: Key general:default-reverb not found AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) MMDevApiMsgProc: Starting message loop [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com Could not locate symbol glEnableClientStateiEXT Could not locate symbol glDisableClientStateiEXT Could not locate symbol glGetFloati_vEXT Could not locate symbol glGetDoublei_vEXT Could not locate symbol glGetPointeri_vEXTNote that the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Additionally, "Could not locate symbol" at the bottom also occurs each time. Finally, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist - the "Could not load OpenAL library" message from it probably is a red herring; the earlier Could not open ALC device and "MMDevApiOpenPlayback: Device init failed: 0x80004005" are probably more useful.
On further inspection,
here's the code that generates that error. Note that 0x80004005 is a completely useless error code; it just represents E_FAIL which means "Unspecified failure".A successful OpenAL startup on my machine looks like this, for reference:
AL lib: (II) alc_initconfig: Supported backends: mmdevapi, dsound, winmm, null, wave AL lib: (II) GetConfigValue: Key general:disable-cpu-exts not found AL lib: (II) FillCPUCaps: Got caps: SSE AL lib: (II) GetConfigValue: Key general:rt-prio not found AL lib: (II) GetConfigValue: Key general:resampler not found AL lib: (II) GetConfigValue: Key general:trap-al-error not found AL lib: (II) GetConfigValue: Key general:trap-alc-error not found AL lib: (II) GetConfigValue: Key reverb:boost not found AL lib: (II) GetConfigValue: Key reverb:emulate-eax not found AL lib: (II) GetConfigValue: Key general:drivers not found AL lib: (II) MMDevApiMsgProc: Starting message thread AL lib: (II) MMDevApiMsgProc: Starting message loop AL lib: (II) alc_initconfig: Initialized backend "mmdevapi" AL lib: (II) alc_initconfig: Added "mmdevapi" for playback AL lib: (II) alc_initconfig: Initialized backend "dsound" AL lib: (II) alc_initconfig: Added "dsound" for capture AL lib: (II) GetConfigValue: Key general:excludefx not found AL lib: (II) GetConfigValue: Key general:default-reverb not found AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (II) MMDevApiMsgProc: Got message 1024 AL lib: (II) alcOpenDevice: Created device 0000000025070090, "Speakers (High Definition Audio Device)" AL lib: (II) UpdateDeviceParams: Pre-reset: Stereo, Float, 44100hz, 1024 update size x4 AL lib: (II) MMDevApiMsgProc: Got message 1025 AL lib: (II) UpdateDeviceParams: Post-reset: Stereo, Float, 44100hz, 896 update size x4 AL lib: (II) GetConfigValue: Key general:layout_stereo not found AL lib: (II) GetConfigValue: Key general:layout not found AL lib: (II) GetConfigValue: Key general:hrtf not found AL lib: (II) UpdateDeviceParams: HRTF disabled AL lib: (II) UpdateDeviceParams: BS2B disabled AL lib: (II) GetConfigValue: Key general:wide-stereo not found AL lib: (II) MMDevApiMsgProc: Got message 1026 AL lib: (II) alcCreateContext: Created context 0000000025088450
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, and with the system environment variable ALSOFT_LOGLEVEL set to 3, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 AL lib: (II) alc_initconfig: Supported backends: mmdevapi, dsound, winmm, null, wave AL lib: (II) GetConfigValue: Key general:disable-cpu-exts not found AL lib: (II) FillCPUCaps: Got caps: SSE AL lib: (II) GetConfigValue: Key general:rt-prio not found AL lib: (II) GetConfigValue: Key general:resampler not found AL lib: (II) GetConfigValue: Key general:trap-al-error not found AL lib: (II) GetConfigValue: Key general:trap-alc-error not found AL lib: (II) GetConfigValue: Key reverb:boost not found AL lib: (II) GetConfigValue: Key reverb:emulate-eax not found AL lib: (II) GetConfigValue: Key general:drivers not found [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) AL lib: (II) MMDevApiMsgProc: Starting message thread AL lib: (II) alc_initconfig: Initialized backend "mmdevapi" AL lib: (II) alc_initconfig: Added "mmdevapi" for playback AL lib: (II) alc_initconfig: Initialized backend "dsound" AL lib: (II) alc_initconfig: Added "dsound" for capture AL lib: (II) GetConfigValue: Key general:excludefx not found AL lib: (II) GetConfigValue: Key general:default-reverb not found AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) MMDevApiMsgProc: Starting message loop [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com Could not locate symbol glEnableClientStateiEXT Could not locate symbol glDisableClientStateiEXT Could not locate symbol glGetFloati_vEXT Could not locate symbol glGetDoublei_vEXT Could not locate symbol glGetPointeri_vEXTNote that the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Additionally, "Could not locate symbol" at the bottom also occurs each time. Finally, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist (as it is only supposed to be located in the temporary natives folder) - the "Could not load OpenAL library" message from it probably is a red herring; the earlier "Could not open ALC device" and "MMDevApiOpenPlayback: Device init failed: 0x80004005" are probably more useful. Also, note that 0x80004005 is a meaningless error code; it just represents E_FAIL which means "Unspecified failure".
After asking the OpenAL mailing list for additional information, it turns out that this is a fairly old OpenAL bug, which was fixed in OpenAL Soft version 1.16. Minecraft is using version 1.15.1 (as LWJGL 2 uses it). This can be fixed by updating OpenAL, either by migrating to LWJGL 3, or just directly updating the OpenAL dll using the one from LWJGL 3 on LWJGL 2.
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
Experienced on Windows Vista, 7, 8, and 10; Java 6, 7, and 8; seems to be non-specific.
WorkaroundIf you experience this bug, you can press F3+T while ingame to reload the sound engine, which should fix it temporarily.
If the bug persists for an extended period of time, you should instead contact 💬 Community Support as it is likely a driver issue or another configuration issue on your end.
Occasionally when resources are loaded, OpenAL fails to start and there is no sound. Generally it works fine, but very rarely it fails.
In that case, it switches to no-sound version.
This is a game log from when it failed to start:[09:46:32] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:32] [Thread-6/INFO]: Initializing LWJGL OpenAL [09:46:32] [Thread-6/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 [09:46:32] [Thread-6/ERROR]: Error in class 'LibraryLWJGLOpenAL' [09:46:32] [Thread-6/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [09:46:32] [Thread-6/WARN]: ERROR MESSAGE: [09:46:32] [Thread-6/INFO]: Could not locate OpenAL library. [09:46:32] [Thread-6/WARN]: STACK TRACE: [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [09:46:32] [Thread-6/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [09:46:32] [Thread-6/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:46:32] [Thread-6/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:46:32] [Thread-6/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [09:46:33] [Sound Library Loader/WARN]: ERROR MESSAGE: [09:46:33] [Sound Library Loader/INFO]: Could not locate OpenAL library. [09:46:33] [Sound Library Loader/INFO]: Starting up SoundSystem... [09:46:33] [Thread-8/INFO]: Switching to No Sound [09:46:33] [Thread-8/INFO]: (Silent Mode)A second reproduction with a debug log4j config, and with -Dorg.lwjgl.util.Debug=true in the launcher args, and with the system environment variable ALSOFT_LOGLEVEL set to 3, gives this:
[21:00:54.655] [Client thread/INFO]: Setting user: pokechu22 [21:00:54.662] [Client thread/DEBUG]: (Session ID is token:<censored>) [21:01:01.502] [Client thread/INFO]: Loaded 482 advancements [21:01:02.371] [Client thread/INFO]: LWJGL Version: 2.9.4 [21:01:02.517] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Initial mode: 1366 x 768 x 32 @60Hz [21:01:02.826] [Client thread/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] MemoryUtil Accessor: AccessorUnsafe [21:01:03.520] [Client thread/INFO]: Reloading ResourceManager: Default, SoundDemo [21:01:07.891] [Client thread/DEBUG]: Replaced sound event location minecraft:music.creative [21:01:07.894] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.creative' to registry [21:01:07.910] [Client thread/DEBUG]: Replaced sound event location minecraft:music.credits [21:01:07.911] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.credits' to registry [21:01:07.914] [Client thread/DEBUG]: Replaced sound event location minecraft:music.dragon [21:01:07.914] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.dragon' to registry [21:01:07.917] [Client thread/DEBUG]: Replaced sound event location minecraft:music.end [21:01:07.917] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.end' to registry [21:01:07.919] [Client thread/DEBUG]: Replaced sound event location minecraft:music.game [21:01:07.920] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.game' to registry [21:01:07.937] [Client thread/DEBUG]: Replaced sound event location minecraft:music.menu [21:01:07.937] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.menu' to registry [21:01:07.942] [Client thread/DEBUG]: Replaced sound event location minecraft:music.nether [21:01:07.943] [Client thread/DEBUG]: Adding duplicate key 'minecraft:music.nether' to registry [21:01:07.955] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_drown [21:01:07.958] [Client thread/WARN]: Missing sound for event: minecraft:entity.player.hurt_on_fire [21:01:07.988] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.221] [Thread-3/INFO]: Initializing LWJGL OpenAL [21:01:08.225] [Thread-3/INFO]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) [21:01:08.236] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: OpenAL64 AL lib: (II) alc_initconfig: Supported backends: mmdevapi, dsound, winmm, null, wave AL lib: (II) GetConfigValue: Key general:disable-cpu-exts not found AL lib: (II) FillCPUCaps: Got caps: SSE AL lib: (II) GetConfigValue: Key general:rt-prio not found AL lib: (II) GetConfigValue: Key general:resampler not found AL lib: (II) GetConfigValue: Key general:trap-al-error not found AL lib: (II) GetConfigValue: Key general:trap-alc-error not found AL lib: (II) GetConfigValue: Key reverb:boost not found AL lib: (II) GetConfigValue: Key reverb:emulate-eax not found AL lib: (II) GetConfigValue: Key general:drivers not found [21:01:08.239] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) AL lib: (II) MMDevApiMsgProc: Starting message thread AL lib: (II) alc_initconfig: Initialized backend "mmdevapi" AL lib: (II) alc_initconfig: Added "mmdevapi" for playback AL lib: (II) alc_initconfig: Initialized backend "dsound" AL lib: (II) alc_initconfig: Added "dsound" for capture AL lib: (II) GetConfigValue: Key general:excludefx not found AL lib: (II) GetConfigValue: Key general:default-reverb not found AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) GetConfigValue: Key general:channels not found AL lib: (II) GetConfigValue: Key general:sample-type not found AL lib: (II) GetConfigValue: Key general:format not found AL lib: (II) GetConfigValue: Key general:frequency not found AL lib: (II) GetConfigValue: Key general:periods not found AL lib: (II) GetConfigValue: Key general:period_size not found AL lib: (II) GetConfigValue: Key general:sources not found AL lib: (II) GetConfigValue: Key general:slots not found AL lib: (II) GetConfigValue: Key general:sends not found AL lib: (II) GetConfigValue: Key general:cf_level not found AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80004005 AL lib: (II) MMDevApiMsgProc: Starting message loop [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.242] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] getPathFromClassLoader: searching for: lwjgl [21:01:08.250] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String) [21:01:08.252] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String) [21:01:08.276] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found 3 OpenAL paths [21:01:08.277] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.282] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll' [21:01:08.348] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\versions\17w18b\17w18b-natives-12740868475532\OpenAL64.dll: Could not open ALC device [21:01:08.349] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll' [21:01:08.350] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll: Could not load OpenAL library (126) [21:01:08.351] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Testing 'OpenAL64.dll' [21:01:08.357] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Found OpenAL at 'OpenAL64.dll' [21:01:08.360] [Thread-3/INFO]: [STDERR]@.(LWJGLUtil.java:514): [LWJGL] Failed to load OpenAL64.dll: Could not open ALC device [21:01:08.362] [Thread-3/ERROR]: Error in class 'LibraryLWJGLOpenAL' [21:01:08.363] [Thread-3/ERROR]: Unable to initialize OpenAL. Probable cause: OpenAL not supported. [21:01:08.363] [Thread-3/WARN]: ERROR MESSAGE: [21:01:08.363] [Thread-3/INFO]: Could not locate OpenAL library. [21:01:08.363] [Thread-3/WARN]: STACK TRACE: [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:156) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:102) [21:01:08.364] [Thread-3/INFO]: org.lwjgl.openal.AL.create(AL.java:206) [21:01:08.364] [Thread-3/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [21:01:08.365] [Thread-3/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121) [21:01:08.598] [Sound Library Loader/WARN]: ERROR MESSAGE: [21:01:08.599] [Sound Library Loader/INFO]: Could not locate OpenAL library. [21:01:08.599] [Sound Library Loader/INFO]: Starting up SoundSystem... [21:01:08.936] [Thread-5/INFO]: Switching to No Sound [21:01:08.938] [Thread-5/INFO]: (Silent Mode) [21:01:09.212] [Sound Library Loader/INFO]: Sound engine started [21:01:28.017] [Client thread/INFO]: Created: 1024x512 textures-atlas [21:01:34.657] [Client thread/INFO]: [STDOUT]@.(NarratorWindows.java:20): Narrator library for x64 successfully loaded [21:01:39.821] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 [21:01:40.861] [Client thread/DEBUG]: Removed channel d8c5b63b-c0f9-4858-8689-ab8f92918a44 because it's not playing anymore [21:01:40.894] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel 558503eb-5f3b-4f9e-a925-f13464f9493a [21:01:41.960] [Client thread/DEBUG]: Removed channel 558503eb-5f3b-4f9e-a925-f13464f9493a because it's not playing anymore [21:01:41.993] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb [21:01:43.028] [Client thread/DEBUG]: Removed channel 730fee9b-fcfd-4261-a427-ce33b23d8dcb because it's not playing anymore [21:02:04.899] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 89e96207-569a-4b2e-9760-a3cceacebd50 [21:02:05.865] [Client thread/DEBUG]: Removed channel 89e96207-569a-4b2e-9760-a3cceacebd50 because it's not playing anymore [21:02:23.418] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu2 for event minecraft:music.menu as channel a78416a6-5d39-4bef-ac14-5092f42eb20d [21:02:24.351] [Client thread/DEBUG]: Removed channel a78416a6-5d39-4bef-ac14-5092f42eb20d because it's not playing anymore [21:02:31.051] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 [21:02:32.017] [Client thread/DEBUG]: Removed channel 2905b576-5eb4-4059-a7e8-83dd15f314c9 because it's not playing anymore [21:02:44.351] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu3 for event minecraft:music.menu as channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 [21:02:45.317] [Client thread/DEBUG]: Removed channel ae31f3f9-fa8b-43a8-8feb-635fc79b3ba1 because it's not playing anymore [21:03:00.152] [Client thread/DEBUG]: Playing sound minecraft:music/menu/menu1 for event minecraft:music.menu as channel 271cec83-88d6-4d8e-a7ac-671891e4a219 [21:03:01.122] [Client thread/DEBUG]: Removed channel 271cec83-88d6-4d8e-a7ac-671891e4a219 because it's not playing anymore [21:03:20.110] [Client thread/DEBUG]: Playing sound minecraft:random/click for event minecraft:ui.button.click as channel b37436b6-ea17-4a68-a2ac-8f704d664e73 [21:03:20.141] [Client thread/INFO]: Stopping! [21:03:20.147] [Client thread/INFO]: SoundSystem shutting down... [21:03:20.348] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com Could not locate symbol glEnableClientStateiEXT Could not locate symbol glDisableClientStateiEXT Could not locate symbol glGetFloati_vEXT Could not locate symbol glGetDoublei_vEXT Could not locate symbol glGetPointeri_vEXTNote that the 3 failures after each instance of "getPathFromClassLoader: searching for:" happen even when audio works successfully - it's likely a platform thing. Additionally, "Could not locate symbol" at the bottom also occurs each time. Finally, note that C:\Users\Pokechu22\AppData\Roaming\.minecraft\OpenAL64.dll does not exist and never should exist (as it is only supposed to be located in the temporary natives folder) - the "Could not load OpenAL library" message from it probably is a red herring; the earlier "Could not open ALC device" and "MMDevApiOpenPlayback: Device init failed: 0x80004005" are probably more useful. Also, note that 0x80004005 is a meaningless error code; it just represents E_FAIL which means "Unspecified failure".
After asking the OpenAL mailing list for additional information, it turns out that this is a fairly old OpenAL bug, which was fixed in OpenAL Soft version 1.16. Minecraft is using version 1.15.1 (as LWJGL 2 uses it). This can be fixed by updating OpenAL, either by migrating to LWJGL 3, or just directly updating the OpenAL dll using the one from LWJGL 3 on LWJGL 2.
I would suggest having Minecraft detect when this happens, and try to restart OpenAL. If it fails multiple times, then it should force a no sound mode. At minimum, a message should be displayed on the title screen in some way, advising the user to use F3+T to reload the sound engine.
MC does attempt to detect this happening in SoundManager, but the sound is loaded in a separate thread from which the catch statement happens. Thread.setUncaughtExceptionHandler should be used instead. Even then, that handler only logs an error and mutes audio; for the general user this behavior isn't entirely obvious ("Why did my game just mute itself‽") although (IIRC) doing that does reload the sound engine when it's unmuted.
MC also has a custom SoundSystemLogger (also declared in SoundManager); that could be used to identify such errors as well.
I experienced a crash with the nexus in dvz, but I think it can be expanded to chests in general.
The nexus in dvz is a enderchest which is shared between all players. As I am writing this, I rewalize that it is a chest issue, not an ednderchest issue.
I experienced a crash with the nexus in dvz, but I think it can be expanded to chests in general.
The nexus in dvz is a enderchest which is shared between all players. As I am writing this, I rewalize that it is a chest issue, not an ednderchest issue.I experienced a crash with the nexus in dvz, but I think it can be expanded to chests in general.
The nexus in dvz is a enderchest which is shared between all players. As I am writing this, I rewalize that it is a chest issue, not an enderchest issue. It seems if 2 players take a item on the same tick, the client crashes.
The comparator will still power Redstone if it is broken.
The comparator will still power Redstone if it is broken. Any Redstone updates to the invalid Redstone fix it.
A player on a pig in a minecart who relogs will cause the minecart to disappear.
A player on a pig in a minecart who relogs will cause the minecart to disappear.
A player on a pig in a minecart who relogs will cause the minecart to disappear.
See this video by sethbling:
http://www.youtube.com/watch?feature=player_detailpage&v=wuZnVmcBY1o#t=218s
A player on a pig in a minecart who relogs will cause the minecart to disappear.
See this video by sethbling:
http://www.youtube.com/watch?feature=player_detailpage&v=wuZnVmcBY1o#t=218s
A few other minor bugs also are shown, but they are custom-entity related and are less important.
A player on a pig in a minecart who relogs will cause the minecart to disappear.
See this video by sethbling:
http://www.youtube.com/watch?feature=player_detailpage&v=wuZnVmcBY1o#t=218sSteps to reproduce:
1. Run command :/summon Pig ~ ~5 ~ {Saddle:1,Riding:{id:Pig,Riding:{id:Pig}}}2. Mount uppermost entity
3. Disconnect/Unload world
4. Join/Load worldResult:
Local game: Deletes all but uppermost entity of the stack
External Server: Decouples uppermost entity from the stack,all other entities remain stacked correctly.A player on a pig in a minecart who relogs will cause the minecart to disappear.
See this video by sethbling:
http://www.youtube.com/watch?feature=player_detailpage&v=wuZnVmcBY1o#t=218sSteps to reproduce:
1. Run this command to create the needed entities:/summon Pig ~ ~5 ~ {Saddle:1,Riding:{id:Pig,Riding:{id:Pig}}}2. Mount uppermost entity
3. Disconnect/Unload world
4. Join/Load worldResult:
Local game: Deletes all but the uppermost entity of the stack
External Server: Decouples the uppermost entity from the stack; all other entities remain stacked correctly.
A player on a pig in a minecart who relogs will cause the minecart to disappear.
See this video by sethbling:
http://www.youtube.com/watch?feature=player_detailpage&v=wuZnVmcBY1o#t=218sSteps to reproduce:
1. Run this command to create the needed entities:/summon Pig ~ ~5 ~ {Saddle:1,Riding:{id:Pig,Riding:{id:Pig}}}2. Mount uppermost entity
3. Disconnect/Unload world
4. Join/Load worldResult:
Local game: Deletes all but the uppermost entity of the stack
External Server: Decouples the uppermost entity from the stack; all other entities remain stacked correctly.A player on a pig in a minecart who relogs will cause the minecart to disappear.
See this video by sethbling.Alternatively, see this video to see what it looks like from another player's perspective.
Steps to reproduce:
1. Run this command to create the needed entities:/summon Pig ~ ~5 ~ {Saddle:1,Riding:{id:Pig,Riding:{id:Pig}}}2. Mount uppermost entity
3. Disconnect/Unload world
4. Join/Load worldResult:
Local game: Deletes all but the uppermost entity of the stack
External Server: Decouples the uppermost entity from the stack; all other entities remain stacked correctly.
Crashed on closing of inventory. It was the nexus in dvz (a modified server that uses vanilla client), which is the equivalent to a large chest. I think that I was pressing 1 and e when I closed it, but im not sure.
Crashed on closing of inventory. It was the nexus in dvz (a modified server that uses vanilla client), which is the equivalent to a large chest. I think that I was pressing 1 and e when I closed it, but im not sure.
EDIT: reproduced in single player. Seems to ocour when you swap and exit the inventory on the same tick.
Crashed on closing of inventory. It was the nexus in dvz (a modified server that uses vanilla client), which is the equivalent to a large chest. I think that I was pressing 1 and e when I closed it, but im not sure.
EDIT: reproduced in single player. Seems to ocour when you swap and exit the inventory on the same tick.
Crashed on closing of inventory. It was the nexus in dvz (a modified server that uses vanilla client), which is the equivalent to a large chest. I think that I was pressing 1 and e when I closed it, but im not sure.
EDIT: reproduced in single player. Seems to ocour when you swap and exit the inventory on the same tick. See Log 2.
Crashed on closing of inventory. It was the nexus in dvz (a modified server that uses vanilla client), which is the equivalent to a large chest. I think that I was pressing 1 and e when I closed it, but im not sure.
EDIT: reproduced in single player. Seems to ocour when you swap and exit the inventory on the same tick. See
Log 2.Crashed on closing of inventory. It was the nexus in dvz (a modified server that uses vanilla client), which is the equivalent to a large chest. I think that I was pressing 1 and e when I closed it, but im not sure.
EDIT: reproduced in single player. Seems to ocour when you swap and exit the inventory on the same tick. See crash-2013-02-28_21.16.25-client
You cant use the scroll wheel in a crash report. Probably the most minor bug ever.
is duplicated by
relates to
is duplicated by
is duplicated by
I crashed while afk on the dvz server. An important thing to note: many/all of the mobs in the report are actualy players.
And I misspelled "unknown".
Unknown crash
I crashed while afk on the dvz server. An important thing to note: many/all of the mobs in the report are actualy players.
And I misspelled "unknown".
I crashed while afk on the dvz server. An important thing to note: many/all of the mobs in the report are actualy players.
And I misspelled "unknown" as unown.OOH I just found that I can edit the title!
I made Minecraft crash while trying to experiment with hash problems!
Of course, that is expected when the items on my hotbar are all cheaty variants (the actual block version of Redstone and repeaters), and I am moving locked chests with pistons... To reproduce, you must reactivate the clock, then stand on the vertical piston. Very interesting bug, probably a side effect of the behavior that was what I was experimenting with. Depending on whether the vertical or horizontal piston is instantly pulling, the crash is easier. Just stand on the block if vertical. My test world constantly crashes now. This device is weird.To use this world, you may need to delete the level.dat and then go to my coordinates.
The locked chests are probably not required, I just was messing around.
This has NOTHING to do with quasiconectivity.
I made Minecraft crash while trying to experiment with hash problems!
Of course, that is expected when the items on my hotbar are all cheaty variants (the actual block version of Redstone and repeaters), and I am moving locked chests with pistons... To reproduce, you must reactivate the clock, then stand on the vertical piston. Very interesting bug, probably a side effect of the behavior that was what I was experimenting with. Depending on whether the vertical or horizontal piston is instantly pulling, the crash is easier. Just stand on the block if vertical. My test world constantly crashes now. This device is weird.To use this world, you may need to delete the level.dat and then go to my coordinates.
The locked chests are probably not required, I just was messing around.Doesn't work with solid blocks, it may need locked chests. Still experimenting.This has NOTHING to do with quasiconectivity.
What I expected to happen was...:
Pistons should only extend when powered by a block that updates them. Blocks that are not touching the piston should not power it (touching diagonally is OK).In this image, the pistons should accept any power from the green blocks, check to see if the orange blocks would notify it before accepting power from them, and not accept power from any of the stone blocks:
What actually happened was...:
Pistons extend when blocks are providing power to the block above them, even if they don't update the piston. In this case, the piston must be updated by another method in order to extend or retract.Example of odd effects this has: http://www.youtube.com/watch?v=JqU0Kmb_bFA
Steps to Reproduce:
1. Place a piston.
2. Put a block on top of it.
3. Put another block on any exposed face of that block.
4. Put a lever on the block you just placed and flip it.
5. Notice that the piston doesn't extend.
6. Place or break any block directly next to the piston.
7. Notice that the piston extends.
8. Flip the lever off.
9. Notice that the piston did not retract.
10. Place or break another block directly next to the piston.
11. Notice that the piston retracts.
Edit: Image now allows for more interesting new types of redstone components and less invasive implementation.
Original:
Moderator NoteDiscussion in regards to this report, such as it
's functionality, usefulness, and comparison with a "BUD Block" (should one be added to the PC edition), is to be done on this subreddit thread.
is duplicated by
is duplicated by
Serverside only.
Serverside only.
Windows cmd.
FencesFence right click
When you rightclick on a fence, it clientside behaves as if the fence took the rightclick, and does nothing else, but serverside it places.
This messes up signs, lets you place blocks in yourself, and annoys my ocd.See: http://youtu.be/Z79WnU7tA9w
EDIT: In 1.6.2 signs are fixed, the other parts aren't though.
Fenceright clickFences can insert a block in you (xray)
When you press tab, it is supposed to list thru all options, clearing the old list for the new one. Instead, it leaves a large amount of text behind if you have more then 1 line used.
To reproduce this:
Type the / character. Then type tab. Note that there are a lot of commands.
Press tab again. The list is shown again.
To see this better, try /scoreboard teams option asdf color and press tab.
It works fine.
Press tab again.
Note the mess it makes.
This is caused (probably) by the method this.mc.ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(stringbuilder.toString(), 1);on line 275 in GUIChat.java (mcp names). It is creating a line of chat that will be overridden, but is only applying one line even though the message may be multiple lines long.When you press tab, it is supposed to list thru all options, clearing the old list for the new one. Instead, it leaves a large amount of text behind if you have more then 1 line used.
To reproduce this:
Type the / character. Then type tab. Note that there are a lot of commands.
Press tab again. The list is shown again.
To see this better, try /scoreboard teams option asdf color and press tab.
It works fine.
Press tab again.
Note the mess it makes.This is caused (probably) by the method
this.mc.ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(stringbuilder.toString(), 1);on line 275 in GUIChat.java (mcp names). It is creating a line of chat that will be overridden, but is only applying one line even though the message may be multiple lines long.
When joining a server, there is some lag. This is normal. But, you might try to type "H*e*llo", which is the following set of keystrokes: tHello. What happens? You open your inventory, despite pressing t first, as all of those are registered as happening on one frame. This isn't an issue when saying "Hi", as the command is tHi.
This is more of an annoyance on bukkit servers with a /server command, as you might type /server survival1 in the hub and end up opening your inventory anyways. It's an annoying timewaste.
It's minor, but it is annoying.
When joining a server, there is some lag. This is normal. But, you might try to type "H*e*llo", which is the following set of keystrokes: tHello. What happens? You open your inventory, despite pressing t first, as all of those are registered as happening on one frame. This isn't an issue when saying "Hi", as the command is tHi.
This is more of an annoyance on bukkit servers with a /server command, as you might type /server survival1 in the hub and end up opening your inventory anyways. It's an annoying timewaste.
This is easiest to reproduce by setting the framerate limit to 10FPS (giving you a 1/6th of a second window), and putting fingers over the t and e keys. Hit t and then e in rapid succession, and you will get the inventory screen (even though you can tell you hit t first).
relates to
When exiting a minecart, and the NW,W,N,NE and E directions are blocked,
it won't exit the player in the S,SE and SW direction even if there are no blocks.It results in the player spawning above/centered from the minecart, even when there is a block above it.
So,thelogics doesnt seem to check every direction, but stops halfway.Also the order is not clockwise (just a detail), but is: North West, West, North, North East....In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomTested:
- Version: 1.7.5 - 1.8 snapshots.
- Gamemode: Creative & Survival
- Changing track direction doesnt make a difference.
When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of *15w36d* appear at the bottom. Older obfuscation is archived []
The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w36d's obfuscation ([jd is used to decompile):Original EntityLivingBase.dismountEntity:
rk, lines 1185 to 1215public void q(rb ☃) { double ☃ = ☃.r; double ☃ = ☃.aZ().b + ☃.J; double ☃ = ☃.t; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.r + ☃); int ☃ = (int)(this.t + ☃); ayq ☃ = aZ().c(☃, 1.0D, ☃); if (this.n.a(☃).isEmpty()) { if (agq.a(this.n, new cj(☃, (int)this.s, ☃))) { a(this.r + ☃, this.s + 1.0D, this.t + ☃); return; } if ((agq.a(this.n, new cj(☃, (int)this.s - 1, ☃))) || (this.n.p(new cj(☃, (int)this.s - 1, ☃)).c().v() == avw.h)) { ☃ = this.r + ☃; ☃ = this.s + 1.0D; ☃ = this.t + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rk, lines 1185 to 1215public void q(rb ☃) { double ☃ = ☃.r; double ☃ = ☃.aZ().b + ☃.J; double ☃ = ☃.t; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //< changed to <= if ((☃ != 0) || (☃ != 0)) { double ☃ = (this.r + ☃); //Changed to double and cast removed double ☃ = (this.t + ☃); //Changed to double and cast removed ayq ☃ = aZ().c(☃, 1.0D, ☃); if (this.n.a(☃).isEmpty()) { if (agq.a(this.n, new cj(☃, this.s, ☃))) { //Removed int cast for this.s a(this.r + ☃, this.s + 1.0D, this.t + ☃); return; } if ((agq.a(this.n, new cj(☃, this.s - 1, ☃))) || (this.n.p(new cj(☃, this.s - 1, ☃)).c().v() == avw.h)) { //Removed int casts for this.s ☃ = this.r + ☃; ☃ = this.s + 1.0D; ☃ = this.t + ☃; } } } } } a(☃, ☃, ☃); }
Player cannot exit minecart on blocks in S,SE,SW directionDismounting does not work to the South, South east, and South west, and is offset in negative quadrants
When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of *15w3
6d* appear at the bottom. Older obfuscation is archived []The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w36d's obfuscation ([jd is used to decompile):Original EntityLivingBase.dismountEntity:
rk, lines 1185to 1215public void q(rb☃) { double ☃ = ☃.r; double ☃ = ☃.aZ().b + ☃.J; double ☃ = ☃.t; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.r+ ☃); int ☃ = (int)(this.t+ ☃); ayq☃ = aZ().c(☃, 1.0D, ☃); if (this.n.a(☃).isEmpty()) { if (agq.a(this.n, new cj(☃, (int)this.s, ☃))) { a(this.r+ ☃, this.s+ 1.0D, this.t+ ☃); return; } if ((agq.a(this.n, new cj(☃, (int)this.s- 1, ☃))) || (this.n.p(new cj(☃, (int)this.s- 1, ☃)).c().v() == avw.h)) { ☃ = this.r+ ☃; ☃ = this.s+ 1.0D; ☃ = this.t+ ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rk, lines 1185to 1215public void q(rb☃) { double ☃ = ☃.r; double ☃ = ☃.aZ().b + ☃.J; double ☃ = ☃.t; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //< changed to <= if ((☃ != 0) || (☃ != 0)) {double☃ = (this.r + ☃); //Changed to double and cast removeddouble☃ = (this.t+ ☃); //Changed to double and cast removed ayq☃ = aZ().c(☃, 1.0D, ☃); if (this.n.a(☃).isEmpty()) { if (agq.a(this.n, new cj(☃, this.s, ☃))) { //Removed int castforthis.sa(this.r+ ☃, this.s+ 1.0D, this.t+ ☃); return; } if ((agq.a(this.n, new cj(☃,this.s- 1, ☃))) || (this.n.p(new cj(☃, this.s- 1, ☃)).c().v() == avw.h)) { //Removed intcastsfor this.s☃ = this.r+ ☃; ☃ = this.s+ 1.0D; ☃ = this.t+ ☃; } } } } } a(☃, ☃, ☃); }When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of *15w37a* appear at the bottom. Older obfuscation is archived []
The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w37a's obfuscation ([jd is used to decompile):Original EntityLivingBase.dismountEntity:
rl, lines 1184 to 1284public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.q + ☃); int ☃ = (int)(this.s + ☃); ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, (int)this.r, ☃))) { a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, (int)this.r - 1, ☃)).a() == awe.h)) { ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rl, lines 1184 to 1214public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //Changed < to <= if ((☃ != 0) || (☃ != 0)) { dobule ☃ = (this.q + ☃); //Changed to double and removed cast dobule ☃ = (this.s + ☃); //Changed to double and removed cast ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, this.r, ☃))) { //Removed int cast on this.r a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, this.r - 1, ☃)).a() == awe.h)) { //Removed int cast on this.r ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }
When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of *15w3
7a* appear at the bottom. Older obfuscation is archived []The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w37a's obfuscation ([jd is used to decompile):Original EntityLivingBase.dismountEntity:
rl, lines 1184 to 1284public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.q + ☃); int ☃ = (int)(this.s + ☃); ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, (int)this.r, ☃))) { a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, (int)this.r - 1, ☃)).a() == awe.h)) { ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rl, lines 1184 to 1214public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //Changed < to <= if ((☃ != 0) || (☃ != 0)) { dobule ☃ = (this.q + ☃); //Changed to double and removed cast dobule ☃ = (this.s + ☃); //Changed to double and removed cast ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, this.r, ☃))) { //Removed int cast on this.r a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, this.r - 1, ☃)).a() == awe.h)) { //Removed int cast on this.r ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of *15w38a* appear at the bottom. Older obfuscation is archived []
The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w38a's obfuscation ([jd is used to decompile):Original EntityLivingBase.dismountEntity:
rl, lines 1184 to 1284public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.q + ☃); int ☃ = (int)(this.s + ☃); ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, (int)this.r, ☃))) { a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, (int)this.r - 1, ☃)).a() == awe.h)) { ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rl, lines 1184 to 1214public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //Changed < to <= if ((☃ != 0) || (☃ != 0)) { dobule ☃ = (this.q + ☃); //Changed to double and removed cast dobule ☃ = (this.s + ☃); //Changed to double and removed cast ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, this.r, ☃))) { //Removed int cast on this.r a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, this.r - 1, ☃)).a() == awe.h)) { //Removed int cast on this.r ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }
When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of
*15w38a*appear at the bottom. Older obfuscation is archived[]The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w38a's obfuscation ([jd is used to decompile):Original EntityLivingBase.dismountEntity:
rl, lines 1184 to 1284public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.q + ☃); int ☃ = (int)(this.s + ☃); ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, (int)this.r, ☃))) { a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, (int)this.r - 1, ☃)).a() == awe.h)) { ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rl, lines 1184 to 1214public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //Changed < to <= if ((☃ != 0) || (☃ != 0)) { dobule ☃ = (this.q + ☃); //Changed to double and removed cast dobule ☃ = (this.s + ☃); //Changed to double and removed cast ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, this.r, ☃))) { //Removed int cast on this.r a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, this.r - 1, ☃)).a() == awe.h)) { //Removed int cast on this.r ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38a appear at the bottom. Older obfuscation is archived here.
The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w38a's obfuscation (jd is used to decompile):Original EntityLivingBase.dismountEntity:
rl, lines 1184 to 1284public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.q + ☃); int ☃ = (int)(this.s + ☃); ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, (int)this.r, ☃))) { a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, (int)this.r - 1, ☃)).a() == awe.h)) { ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rl, lines 1184 to 1214public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //Changed < to <= if ((☃ != 0) || (☃ != 0)) { dobule ☃ = (this.q + ☃); //Changed to double and removed cast dobule ☃ = (this.s + ☃); //Changed to double and removed cast ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, this.r, ☃))) { //Removed int cast on this.r a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, this.r - 1, ☃)).a() == awe.h)) { //Removed int cast on this.r ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }
When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38
aappear at the bottom. Older obfuscation is archived here.The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w38a's obfuscation (jd is used to decompile):Original EntityLivingBase.dismountEntity:
rl, lines 1184 to 1284public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.q + ☃); int ☃ = (int)(this.s + ☃); ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, (int)this.r, ☃))) { a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, (int)this.r - 1, ☃)).a() == awe.h)) { ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rl, lines 1184 to 1214public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //Changed < to <= if ((☃ != 0) || (☃ != 0)) { dobule ☃ = (this.q + ☃); //Changed to double and removed cast dobule ☃ = (this.s + ☃); //Changed to double and removed cast ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, this.r, ☃))) { //Removed int cast on this.r a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, this.r - 1, ☃)).a() == awe.h)) { //Removed int cast on this.r ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }When exiting a minecart (or any other vehicle), and the NW, W, N, NE, and E directions are blocked, the player will exit in the middle of the minecart, even if there is free space in the S, SE, or SW directions.
It results in the player spawning above/centered from the minecart, even when there is a block above it.
In the screenshot, the red and green color show the exit pattern.
Red = Player will never exit here
Green = Player exits on these blocks if there is roomAdditionally, when attempting to dismount a minecart in a quadrant other than +, +, the dismount location is offset by 1 block. (
MC-56361).To reproduce this, put a block in the air with a rail on it in the +, + quadrant, put a minecart on it, and dismount. You will dismount onto the block. Attempt to repeat it in any other quadrant. You will be dismounted in the air next to the block.
The attached world DismountTestWorld.zip
can be used to see this bug in action.
Why this matters
Inaccurate dismount locations make minecarts inherently dangerous. You can build a rail across lava that looks safe, but instead ends up dropping you into lava and causing you to lose your stuff.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38b appear at the bottom. Older obfuscation is archived here.
The entirety of this bug is in the entity dismount code (net.minecraft.entity.EntityLivingBase.dismountEntity(Entity)).
net.minecraft.entity.EntityLivingBase, lines 1501 - 1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity p_110145_1_) { double var3 = p_110145_1_.posX; double var5 = p_110145_1_.getEntityBoundingBox().minY + (double)p_110145_1_.height; double var7 = p_110145_1_.posZ; byte var9 = 1; for (int var10 = -var9; var10 <= var9; ++var10) { for (int var11 = -var9; var11 < var9; ++var11) { if (var10 != 0 || var11 != 0) { int var12 = (int)(this.posX + (double)var10); int var13 = (int)(this.posZ + (double)var11); AxisAlignedBB var2 = this.getEntityBoundingBox().offset((double)var10, 1.0D, (double)var11); if (this.worldObj.func_147461_a(var2).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY, var13))) { this.setPositionAndUpdate(this.posX + (double)var10, this.posY + 1.0D, this.posZ + (double)var11); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(var12, (int)this.posY - 1, var13)) || this.worldObj.getBlockState(new BlockPos(var12, (int)this.posY - 1, var13)).getBlock().getMaterial() == Material.water) { var3 = this.posX + (double)var10; var5 = this.posY + 1.0D; var7 = this.posZ + (double)var11; } } } } } this.setPositionAndUpdate(var3, var5, var7); }Now, that code is obfuscated pretty badly, so here's a version with renamed variables:
EntityLivingBase.dismountEntity, variables renamed/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ < testRange; ++offsetZ) { if (offsetX != 0 || offsetZ != 0) { int x = (int)(this.posX + (double)offsetX); int z = (int)(this.posZ + (double)offsetZ); AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) //Gets colision boxes of all blocks intersecting with the aabb. { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY, z))) { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, (int)this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, (int)this.posY - 1, z)).getBlock().getMaterial() == Material.water) { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }It should be fairly obvious why dismounting doesn't work to the south: the loop for offsetZ uses only <, meaning that it only checks offsets of -1 and 0!
The fix is just to change < to <=. Then, it's possible to dismount to the south.The second half (offset dismounting on negative quadrants) is more subtle. It's related to the way that the block position checks occur. Specifically, note that x and z are {{int}}s.
Well, posX and posZ are usually offset by .5. And, (int)(-1.5 - 1) is -2, rather than -3. That causes the tested block to be offset by one, meaning that the teleported location is off by one. Here's an ideone demo.
This is also an easy fix, though. BlockPos has a constructor that takes double}}s rather than {{int}}s, and it automatically gets the correct value (it floors it). So, all that needs to be done make {{x and z doubles, and remove the other int casts on posY in the BlockPos constructor calls.
Here's code with both of these issues corrected:
EntityLivingBase corrected, lines 1501-1541/** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity dismountedFrom) { double dismountedX = dismountedFrom.posX; double dismountedY = dismountedFrom.getEntityBoundingBox().minY + (double)dismountedFrom.height; double dismountedZ = dismountedFrom.posZ; byte testRange = 1; for (int offsetX = -testRange; offsetX <= testRange; ++offsetX) { for (int offsetZ = -testRange; offsetZ <= testRange; ++offsetZ) //Changed < to <= { if (offsetX != 0 || offsetZ != 0) { double x = (this.posX + offsetX); //Changed int to double and removed cast double z = (this.posZ + offsetZ); //Changed int to double and removed cast AxisAlignedBB aabb = this.getEntityBoundingBox().offset((double)offsetX, 1.0D, (double)offsetZ); if (this.worldObj.func_147461_a(aabb).isEmpty()) { if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY, z))) //Removed posY cast { this.setPositionAndUpdate(this.posX + (double)offsetX, this.posY + 1.0D, this.posZ + (double)offsetZ); return; } if (World.doesBlockHaveSolidTopSurface(this.worldObj, new BlockPos(x, this.posY - 1, z)) || this.worldObj.getBlockState(new BlockPos(x, this.posY - 1, z)).getBlock().getMaterial() == Material.water) //Removed posY casts { dismountedX = this.posX + (double)offsetX; dismountedY = this.posY + 1.0D; dismountedZ = this.posZ + (double)offsetZ; } } } } } this.setPositionAndUpdate(dismountedX, dismountedY, dismountedZ); }
Here are the code snippets from above with 15w38b's obfuscation (jd is used to decompile):Original EntityLivingBase.dismountEntity:
rl, lines 1184 to 1284public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ < ☃; ☃++) { if ((☃ != 0) || (☃ != 0)) { int ☃ = (int)(this.q + ☃); int ☃ = (int)(this.s + ☃); ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, (int)this.r, ☃))) { a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, (int)this.r - 1, ☃)).a() == awe.h)) { ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }Fixed version:
rl, lines 1184 to 1214public void q(rc ☃) { double ☃ = ☃.q; double ☃ = ☃.aZ().b + ☃.I; double ☃ = ☃.s; int ☃ = 1; for (int ☃ = -☃; ☃ <= ☃; ☃++) { for (int ☃ = -☃; ☃ <= ☃; ☃++) { //Changed < to <= if ((☃ != 0) || (☃ != 0)) { dobule ☃ = (this.q + ☃); //Changed to double and removed cast dobule ☃ = (this.s + ☃); //Changed to double and removed cast ayz ☃ = aZ().c(☃, 1.0D, ☃); if (this.m.a(☃).isEmpty()) { if (agr.a(this.m, new cj(☃, this.r, ☃))) { //Removed int cast on this.r a(this.q + ☃, this.r + 1.0D, this.s + ☃); return; } if ((agr.a(this.m, new cj(☃, (int)this.r - 1, ☃))) || (this.m.p(new cj(☃, this.r - 1, ☃)).a() == awe.h)) { //Removed int cast on this.r ☃ = this.q + ☃; ☃ = this.r + 1.0D; ☃ = this.s + ☃; } } } } } a(☃, ☃, ☃); }
I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode.
Did not test on multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode).
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode. This also occurs in multiplayer and single player.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode. This also occurs in multiplayer and single player.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply {{play}}ing it again, but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of $version appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply
{{play}}ing it again, but probably the sound is getting played before it is removed.Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of
$version appearat the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35
bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx☃){ if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)){ this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null){ o(); azu☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; }else{ this.aH.e(); //This is resumeSounds;line 861.n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e(){ for (String ☃ : this.h.keySet()){ b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f(){ for (String ☃ : this.h.keySet()){ b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e(){ for (String ☃ : this.h.keySet()){ b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃);pausedSounds.add(☃); } } public void f(){ for (String☃ :pausedSounds){ b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); }pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35e appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35e's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azl.a, lines 835 to 864public void a(bcb ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bci(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbm(null); } if ((☃ instanceof bci)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azy ☃ = new azy(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃2603, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 861 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvj, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
5eappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35e's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azl.a, lines 835to 864public void a(bcb☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bci(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbm(null); } if ((☃ instanceof bci)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o();azy☃ = newazy(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 861n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvj, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w36d appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w36d's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azo.a, lines 838 to 867public void a(bce ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcl(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bbp(null); } if ((☃ instanceof bcl)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bab ☃ = new bab(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 864 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvm, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvmList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
6dappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w36d's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azo.a, lines 838to 867public void a(bce☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcl(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bbp(null); } if ((☃ instanceof bcl)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bab☃ = new bab(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 864n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvm, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvmList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w37a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w37a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcn, lines 837 to 866public void a(bcn ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcu(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bby(null); } if ((☃ instanceof bcu)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bak ☃ = new bak(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
7a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w37a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcn, lines 837 to 866public void a(bcn☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcu(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bby(null); } if ((☃ instanceof bcu)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bak☃ = new bak(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863.n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38
aappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
8b appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39
bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 837 to 866public void a(bcs ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcz(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcd(null); } if ((☃ instanceof bcz)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bap ☃ = new bap(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwa, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwaList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w
39cappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 837to 866public void a(bcs☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcz(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcd(null); } if ((☃ instanceof bcz)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bap☃ = new bap(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r= false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwa, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwaList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w41b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w41b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 840 to 869public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.u.ao = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 866. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
1bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w41b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 840to 869public void a(bcr☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.u.ao = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bao☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 866.n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbm, lines 849 to 878public void a(bec ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bej(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdn(null); } if ((☃ instanceof bej)) { this.u.ao = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bbz ☃ = new bbz(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxq, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxqList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43
aappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbm, lines 849 to 878public void a(bec☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bej(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdn(null); } if ((☃ instanceof bej)) { this.u.ao= false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bbz☃ = new bbz(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxq, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxqList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbp, lines 849 to 878public void a(beh ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new beo(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bds(null); } if ((☃ instanceof beo)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcc ☃ = new bcc(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbp, lines 849 to 878public void a(beh☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new beo(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bds(null); } if ((☃ instanceof beo)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcc☃ = new bcc(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849 to 878public void a(bel ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg ☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43
bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849 to 878public void a(bel ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg ☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃2603}); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849 to 878public void a(bel ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg ☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
3cappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849to 878public void a(bel☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines373to384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w44b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w44b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃2603= ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w44b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
4bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap= false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false;} else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w45a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w45a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 850 to 879public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bea(null); } if ((☃ instanceof bew)) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byf, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
5a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w45a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 850 to 879public void a(bep☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bea(null); } if ((☃ instanceof bew)) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byf, lines 412to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w46a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w46a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bby, lines 850 to 879public void a(beo ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bev(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bdz(null); } if ((☃ instanceof bev)) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bck ☃ = new bck(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bye, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byeList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
6a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w46a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bby, lines 850to 879public void a(beo☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bev(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bdz(null); } if ((☃ instanceof bev)){this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bck☃ = new bck(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bye, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byeList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 879public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 879public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49
aappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI,
anda chest all work.Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w
49b appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w51b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w51b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcb, lines 851 to 880public void a(ber ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bey(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bec(null); } if (((☃ instanceof bey)) || ((☃ instanceof bgh))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byk, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bykList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 1
5w51bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w51b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcb, lines 851to 880public void a(ber☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bey(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bec(null); } if (((☃ instanceof bey)) || ((☃ instanceof bgh))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃2603, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byk, lines 417to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bykList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w02a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w02a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 858 to 887public void a(bey ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcu ☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byr, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byrList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w0
2a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w02a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 858 to 887public void a(bey ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcu ☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byr, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byrList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w03a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w03a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 858 to 887public void a(bey ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcu ☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byr, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byrList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w0
3a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w03a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 858 to 887public void a(bey☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcu☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byr, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byrList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w05a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w05a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcd, lines 858 to 887public void a(bez ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bfg(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bek(null); } if (((☃ instanceof bfg)) || ((☃ instanceof bgp))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcv ☃ = new bcv(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byt, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bytList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w05
aappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w05a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcd, lines 858to 887public void a(bez☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bfg(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bek(null); } if (((☃ instanceof bfg)) || ((☃ instanceof bgp))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) {o(); bcv☃ = new bcv(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byt, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bytList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w05b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w05b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 864 to 893public void a(bey ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { p(); bcu ☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aL.e(); // This is resumeAllSounds, line 890 o(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bys, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bysList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w0
5b appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w05b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 864 to 893public void a(bey☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { p(); bcu☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aL.e(); // This is resumeAllSounds, line 890 o(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bys, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bysList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w07b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w07b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bce, lines 864 to 893public void a(bfa ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bfh(); } else if ((☃ == null) && (this.h.bP() <= 0.0F)) { ☃ = new bel(null); } if (((☃ instanceof bfh)) || ((☃ instanceof bgq))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { p(); bcw ☃ = new bcw(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aL.e(); // This is resumeAllSounds, line 890 o(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byu, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byuList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w07b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w07b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bce, lines 864 to 893public void a(bfa ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bfh(); } else if ((☃ == null) && (this.h.bP() <= 0.0F)) { ☃ = new bel(null); } if (((☃ instanceof bfh)) || ((☃ instanceof bgq))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { p(); bcw ☃ = new bcw(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aL.e(); // This is resumeAllSounds, line 890 o(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byu, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byuList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 1.9-pre1 appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 1.9-pre1's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bce, lines 864 to 893public void a(bfa ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bfh(); } else if ((☃ == null) && (this.h.bP() <= 0.0F)) { ☃ = new bel(null); } if (((☃ instanceof bfh)) || ((☃ instanceof bgq))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { p(); bcw ☃ = new bcw(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃2603); this.s = false; } else { this.aL.e(); // This is resumeAllSounds, line 890 o(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byu, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byuList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 1.9-pre1 appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized depending on if it's called from a separate thread, but I'm guessing not since it isn't currently needed; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 1.9-pre1's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bce, lines 864 to 893public void a(bfa ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bfh(); } else if ((☃ == null) && (this.h.bP() <= 0.0F)) { ☃ = new bel(null); } if (((☃ instanceof bfh)) || ((☃ instanceof bgq))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { p(); bcw ☃ = new bcw(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aL.e(); // This is resumeAllSounds, line 890 o(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byu, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byuList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
Windows 7 64 bit
All
relates to
When the Minecraft window is resized while still ingame (and the center of the window changes), the player will start to spin until a GUI is opened and closed. The player can still move the mouse / use the movement keys / place blocks, but they will spin while doing so.
The only way to resize the window while keeping ingame focus is by using the WindowsKey + ArrowKey shortcuts.
1. Move the Minecraft window to the left side of the screen with WindowsKey + Left.
2. Put the mouse back into the Minecraft window.
3. Maximize the Minecraft windowwith WindowsKey +Up.
4. You will experience this bug.(For extra fun, run /effect @p minecraft:nausea before hand, but this is not needed).
I believe that the root cause of this issue is that the "Center of the screen" location that the mouse jumps to each tick isn't getting updated on screen resize properly, but the location that is used to compute the movement of the mouse is.
When the Minecraft window is resized while still ingame (and the center of the window changes), the player will start to spin until a GUI is opened and closed. The player can still move the mouse / use the movement keys / place blocks, but they will spin while doing so.
The only way to resize the window while keeping ingame focus is by using the WindowsKey + ArrowKey shortcuts.
1. Move the Minecraft window to the left side of the screen with WindowsKey + Left. This will put the window fully vertically on the side, and will resize the window.
2. Put the mouse back into the Minecraft window.
3. Move the window back to the center with WindowsKey + Right.
4. You will experience this bug.(For extra fun, run /effect @p minecraft:nausea before hand, but this is not needed).
I believe that the root cause of this issue is that the "Center of the screen" location that the mouse jumps to each tick isn't getting updated on screen resize properly, but the location that is used to compute the movement of the mouse is.
java version "1.8.0_
40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
Microsoft Windows8.1 Pro
6.3.9600 N/ABuild9600java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b15, mixed mode)
Microsoft Windows 10 Pro
10.0.15063 Build 15063
Screen Resolution 1366 x 768 x 60 hertz
When you die, the chat window closes.
It removes the message you are typing.If you are on a pvp server trying to report a hacker, this becomes a huge pain.Also, if you are lagging, and you die serverside, any chat you send will be ignored.
What I expected to happen: I could continue typing after I died, and finish the current message.What happened instead: The chat window was rudely closed and overridden by the "YOU DIED" window.
To reproduce:
Go onto a multiplayer server.
Ask someone to kill you.
Put a message into chat mid-process.
In the past that wasn't the case, which is my justification of this as a bug.
The greatest solution to this would be to also let you open the chat window while dead, but that could feasibly cause several problems.When one dies, the chat window is forcibly overwritten by the Game Over screen, deleting any message that was being typed. This is extremely frustrating when, for example, trying to report a hacker in PVP since you lose the name.
This did not happen in the past (versions prior to 1.8), but started happening in 1.9. (Note: this issue has 1.6.2 in its effects version, but on those versions it only happened on spigot servers, not vanilla servers; it happens on vanilla now).
Additionally, this can happen in single-player, not just multiplayer. Of course, in single player it's generally less important since you won't usually be typing in chat, but it still happens (you can test the issue with a command block /kill-ing you).
Text in chat iscleared whendeadChat UI is forcibly cleared when killed
When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
I've attached a sound recording of this glitch in action. It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Debug logs
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
Sound recording
I've attached a sound recording of this glitch in action (ItemPlopsGlitch.mp3
). It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
Cause
1.9.4 obfuscation is used in all places where obfuscation is provided; no 1.8 obfuscation is provided right now.
The root cause is that there are two places where picking up an item makes a sound (ignoring /give's code for it). First, EntityItem.onCollideWithPlayer(EntityPlayer) (rr.d(zj)) calls worldObj.playSound (a(DDDLng;Lni;FFZ)). But it also sends a Collect Item packet. When that packet is processed in NetHandlerPlayClient.handleCollectItem (bkq.a(ic), a sound is also played. That duplication causes this issue; the easiest fix is just to remove one of the two (I recommend the one in handleCollectItem - the one on the item pickup side mutes the sound if the item is silent).
But... the same code is present in 1.8 more or less, yet this issue does not occur. Why? Well... let's look at what each version does in both parts.
EntityItem.onCollideWithPlayer
Both have very similar calls in the middle of this method. Compare, though:
1.8if (!this.isSlient()) { this.worldObj.playSoundAtEntity(entityIn, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }1.9.4if (!this.isSilent()) { this.worldObj.playSound((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }Now, the changes here are probably part of some sound engine re-factoring that happened in 1.9 (and probably, the actual method names are the same in the real code). Let's look at the code for these methods:
1.8/** * Plays a sound at the entity's position. Args: entity, sound, volume * (relative to 1.0), and frequency (or pitch, also relative to 1.0). */ public void playSoundAtEntity(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { for (int var5 = 0; var5 < this.worldAccesses.size(); ++var5) { ((IWorldAccess) this.worldAccesses.get(var5)).playSound(p_72956_2_, p_72956_1_.posX, p_72956_1_.posY, p_72956_1_.posZ, p_72956_3_, p_72956_4_); } }1.9.4public void playSound(EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) { for (int i = 0; i < this.eventListeners.size(); ++i) { ((IWorldEventListener)this.eventListeners.get(i)).playSound(player, soundIn, category, x, y, z, volume, pitch); } }More renaming, but the gist is the same. IWorldAccess and IWorldEventListener (ahv) are the same thing, just renamed. There are several implementations. While it isn't entirely clear which is used when, there seems to be one that's used clientside and one that's used serverside (and a path debugging on in 1.9 that isn't important). Here are the implementations:
WorldManager (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { this.mcServer.getConfigurationManager().sendToAllNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionId(), new S29PacketSoundEffect(soundName, x, y, z, volume, pitch)); }RenderGlobal (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { }WorldManager (lr) (1.9.4)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { this.mcServer.getPlayerList().sendToAllNearExcept(player, x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionType().getId(), new SPacketSoundEffect(soundIn, category, x, y, z, volume, pitch)); }RenderGlobal (bnl) (1.8)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { }In both cases, the clientside implementation is empty. Now, the serverside implementation did change between 1.8 and 1.9.4, to exclude sending to a specific player, but in this case the player is null so that change doesn't matter. So, the bug probably isn't in this part of the code.
NetHandlerPlayClient.handleCollectItem
OK, so if the bug isn't on that part, what about NetHandlerPlayClient? Well, both have this logic:
1.8if (var2 != null) { if (var2 instanceof EntityXPOrb) { this.clientWorldController.playSoundAtEntity(var2, "random.orb", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } else { this.clientWorldController.playSoundAtEntity(var2, "random.pop", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, var2, (Entity) var3, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.func_149354_c()); }1.9.4if (entity != null) { if (entity instanceof EntityXPOrb) { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_experience_orb_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } else { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, entity, entitylivingbase, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.getCollectedItemEntityID()); }Very similar, yes? But there's a notable difference... not there, though.
See, in 1.8, clientWorldController.playSoundAtEntity refers to World.playSoundAtEntity. And, as previously shown, that goes through the IWorldAccess}}es. And the client version, {{RenderGlobal, does nothing.
But in 1.9.4, that specific playSound method is both defined in World (aht/a (DDDLng;Lni;FFZ)V) and overriden in WorldClient (bks/a (DDDLng;Lni;FFZ)V). The World (aht) implementation does nothing:
World.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { }but WorldClient (bks) does something very direct:
WorldClient.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { double d0 = this.mc.getRenderViewEntity().getDistanceSq(x, y, z); PositionedSoundRecord positionedsoundrecord = new PositionedSoundRecord(soundIn, category, volume, pitch, (float) x, (float) y, (float) z); if (distanceDelay && d0 > 100.0D) { double d1 = Math.sqrt(d0) / 40.0D; this.mc.getSoundHandler().playDelayedSound(positionedsoundrecord, (int) (d1 * 20.0D)); } else { this.mc.getSoundHandler().playSound(positionedsoundrecord); } }Note that, unlike in 1.8, that method actually works. So the playsound call there actually plays the sound, meaning it is played in both places.
TLDR
In both 1.8 and 1.9.4, there is logic to play the pickup sound in two places. However, in 1.8, one of the places it played the sound (when handling the pickup packet) used a method that did nothing (on the client side, which is the only place it would be called in that context). In 1.9.4, both places actually call functional methods, meaning that the sound plays twice.
Fix
The easiest and most logical fix would be to remove the code to play sounds from the handler for the collect item packet. All collectables already make the sound when collected, so it's redundant anyway. As an added benefit, this means that items which are set as silent will not make noise when picked up.
NetHandlerPlayClient.handleCollectItem(SPacketCollectItem)} is obfuscated as {{bkq/a (Lic;)V (bkq.a(ic)). The code that needs to be deleted is on lines 676 through 680.
When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Debug logs
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
Sound recording
I've attached a sound recording of this glitch in action (ItemPlopsGlitch.mp3
). It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
Cause
1.9.4 obfuscation is used in all places where obfuscation is provided; no 1.8 obfuscation is provided right now.
The root cause is that there are two places where picking up an item makes a sound (ignoring /give's code for it). First, EntityItem.onCollideWithPlayer(EntityPlayer) (rr.d(zj)) calls worldObj.playSound (a(DDDLng;Lni;FFZ)). But it also sends a Collect Item packet. When that packet is processed in NetHandlerPlayClient.handleCollectItem (bkq.a(ic), a sound is also played. That duplication causes this issue; the easiest fix is just to remove one of the two (I recommend the one in handleCollectItem - the one on the item pickup side mutes the sound if the item is silent).
But... the same code is present in 1.8 more or less, yet this issue does not occur. Why? Well... let's look at what each version does in both parts.
EntityItem.onCollideWithPlayer
Both have very similar calls in the middle of this method. Compare, though:
1.8if (!this.isSlient()) { this.worldObj.playSoundAtEntity(entityIn, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }1.9.4if (!this.isSilent()) { this.worldObj.playSound((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }Now, the changes here are probably part of some sound engine re-factoring that happened in 1.9 (and probably, the actual method names are the same in the real code). Let's look at the code for these methods:
1.8/** * Plays a sound at the entity's position. Args: entity, sound, volume * (relative to 1.0), and frequency (or pitch, also relative to 1.0). */ public void playSoundAtEntity(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { for (int var5 = 0; var5 < this.worldAccesses.size(); ++var5) { ((IWorldAccess) this.worldAccesses.get(var5)).playSound(p_72956_2_, p_72956_1_.posX, p_72956_1_.posY, p_72956_1_.posZ, p_72956_3_, p_72956_4_); } }1.9.4public void playSound(EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) { for (int i = 0; i < this.eventListeners.size(); ++i) { ((IWorldEventListener)this.eventListeners.get(i)).playSound(player, soundIn, category, x, y, z, volume, pitch); } }More renaming, but the gist is the same. IWorldAccess and IWorldEventListener (ahv) are the same thing, just renamed. There are several implementations. While it isn't entirely clear which is used when, there seems to be one that's used clientside and one that's used serverside (and a path debugging on in 1.9 that isn't important). Here are the implementations:
WorldManager (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { this.mcServer.getConfigurationManager().sendToAllNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionId(), new S29PacketSoundEffect(soundName, x, y, z, volume, pitch)); }RenderGlobal (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { }WorldManager (lr) (1.9.4)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { this.mcServer.getPlayerList().sendToAllNearExcept(player, x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionType().getId(), new SPacketSoundEffect(soundIn, category, x, y, z, volume, pitch)); }RenderGlobal (bnl) (1.8)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { }In both cases, the clientside implementation is empty. Now, the serverside implementation did change between 1.8 and 1.9.4, to exclude sending to a specific player, but in this case the player is null so that change doesn't matter. So, the bug probably isn't in this part of the code.
NetHandlerPlayClient.handleCollectItem
OK, so if the bug isn't on that part, what about NetHandlerPlayClient? Well, both have this logic:
1.8if (var2 != null) { if (var2 instanceof EntityXPOrb) { this.clientWorldController.playSoundAtEntity(var2, "random.orb", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } else { this.clientWorldController.playSoundAtEntity(var2, "random.pop", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, var2, (Entity) var3, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.func_149354_c()); }1.9.4if (entity != null) { if (entity instanceof EntityXPOrb) { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_experience_orb_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } else { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, entity, entitylivingbase, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.getCollectedItemEntityID()); }Very similar, yes? But there's a notable difference... not there, though.
See, in 1.8, clientWorldController.playSoundAtEntity refers to World.playSoundAtEntity. And, as previously shown, that goes through the
IWorldAccess}}es. And the client version,{{RenderGlobal, does nothing.But in 1.9.4, that specific playSound method is both defined in World (aht/a (DDDLng;Lni;FFZ)V) and overriden in WorldClient (bks/a (DDDLng;Lni;FFZ)V). The World (aht) implementation does nothing:
World.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { }but WorldClient (bks) does something very direct:
WorldClient.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { double d0 = this.mc.getRenderViewEntity().getDistanceSq(x, y, z); PositionedSoundRecord positionedsoundrecord = new PositionedSoundRecord(soundIn, category, volume, pitch, (float) x, (float) y, (float) z); if (distanceDelay && d0 > 100.0D) { double d1 = Math.sqrt(d0) / 40.0D; this.mc.getSoundHandler().playDelayedSound(positionedsoundrecord, (int) (d1 * 20.0D)); } else { this.mc.getSoundHandler().playSound(positionedsoundrecord); } }Note that, unlike in 1.8, that method actually works. So the playsound call there actually plays the sound, meaning it is played in both places.
TLDR
In both 1.8 and 1.9.4, there is logic to play the pickup sound in two places. However, in 1.8, one of the places it played the sound (when handling the pickup packet) used a method that did nothing (on the client side, which is the only place it would be called in that context). In 1.9.4, both places actually call functional methods, meaning that the sound plays twice.
Fix
The easiest and most logical fix would be to remove the code to play sounds from the handler for the collect item packet. All collectables already make the sound when collected, so it's redundant anyway. As an added benefit, this means that items which are set as silent will not make noise when picked up.
NetHandlerPlayClient.handleCollectItem(SPacketCollectItem)
} is obfuscated as {{bkq/a (Lic;)V(bkq.a(ic)). The code that needs to be deleted is on lines 676 through 680.When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Debug logs
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
Sound recording
I've attached a sound recording of this glitch in action (ItemPlopsGlitch.mp3
). It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
Cause
1.9.4 obfuscation is used in all places where obfuscation is provided; no 1.8 obfuscation is provided right now.
The root cause is that there are two places where picking up an item makes a sound (ignoring /give's code for it). First, EntityItem.onCollideWithPlayer(EntityPlayer) (rr.d(zj)) calls worldObj.playSound (a(DDDLng;Lni;FFZ)). But it also sends a Collect Item packet. When that packet is processed in NetHandlerPlayClient.handleCollectItem (bkq.a(ic), a sound is also played. That duplication causes this issue; the easiest fix is just to remove one of the two (I recommend the one in handleCollectItem - the one on the item pickup side mutes the sound if the item is silent).
But... the same code is present in 1.8 more or less, yet this issue does not occur. Why? Well... let's look at what each version does in both parts.
EntityItem.onCollideWithPlayer
Both have very similar calls in the middle of this method. Compare, though:
1.8if (!this.isSlient()) { this.worldObj.playSoundAtEntity(entityIn, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }1.9.4if (!this.isSilent()) { this.worldObj.playSound((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }Now, the changes here are probably part of some sound engine re-factoring that happened in 1.9 (and probably, the actual method names are the same in the real code). Let's look at the code for these methods:
1.8/** * Plays a sound at the entity's position. Args: entity, sound, volume * (relative to 1.0), and frequency (or pitch, also relative to 1.0). */ public void playSoundAtEntity(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { for (int var5 = 0; var5 < this.worldAccesses.size(); ++var5) { ((IWorldAccess) this.worldAccesses.get(var5)).playSound(p_72956_2_, p_72956_1_.posX, p_72956_1_.posY, p_72956_1_.posZ, p_72956_3_, p_72956_4_); } }1.9.4public void playSound(EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) { for (int i = 0; i < this.eventListeners.size(); ++i) { ((IWorldEventListener)this.eventListeners.get(i)).playSound(player, soundIn, category, x, y, z, volume, pitch); } }More renaming, but the gist is the same. IWorldAccess and IWorldEventListener (ahv) are the same thing, just renamed. There are several implementations. While it isn't entirely clear which is used when, there seems to be one that's used clientside and one that's used serverside (and a path debugging on in 1.9 that isn't important). Here are the implementations:
WorldManager (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { this.mcServer.getConfigurationManager().sendToAllNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionId(), new S29PacketSoundEffect(soundName, x, y, z, volume, pitch)); }RenderGlobal (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { }WorldManager (lr) (1.9.4)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { this.mcServer.getPlayerList().sendToAllNearExcept(player, x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionType().getId(), new SPacketSoundEffect(soundIn, category, x, y, z, volume, pitch)); }RenderGlobal (bnl) (1.8)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { }In both cases, the clientside implementation is empty. Now, the serverside implementation did change between 1.8 and 1.9.4, to exclude sending to a specific player, but in this case the player is null so that change doesn't matter. So, the bug probably isn't in this part of the code.
NetHandlerPlayClient.handleCollectItem
OK, so if the bug isn't on that part, what about NetHandlerPlayClient? Well, both have this logic:
1.8if (var2 != null) { if (var2 instanceof EntityXPOrb) { this.clientWorldController.playSoundAtEntity(var2, "random.orb", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } else { this.clientWorldController.playSoundAtEntity(var2, "random.pop", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, var2, (Entity) var3, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.func_149354_c()); }1.9.4if (entity != null) { if (entity instanceof EntityXPOrb) { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_experience_orb_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } else { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, entity, entitylivingbase, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.getCollectedItemEntityID()); }Very similar, yes? But there's a notable difference... not there, though.
See, in 1.8, clientWorldController.playSoundAtEntity refers to World.playSoundAtEntity. And, as previously shown, that goes through the IWorldAccess es. And the client version, RenderGlobal, does nothing.
But in 1.9.4, that specific playSound method is both defined in World (aht/a (DDDLng;Lni;FFZ)V) and overriden in WorldClient (bks/a (DDDLng;Lni;FFZ)V). The World (aht) implementation does nothing:
World.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { }but WorldClient (bks) does something very direct:
WorldClient.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { double d0 = this.mc.getRenderViewEntity().getDistanceSq(x, y, z); PositionedSoundRecord positionedsoundrecord = new PositionedSoundRecord(soundIn, category, volume, pitch, (float) x, (float) y, (float) z); if (distanceDelay && d0 > 100.0D) { double d1 = Math.sqrt(d0) / 40.0D; this.mc.getSoundHandler().playDelayedSound(positionedsoundrecord, (int) (d1 * 20.0D)); } else { this.mc.getSoundHandler().playSound(positionedsoundrecord); } }Note that, unlike in 1.8, that method actually works. So the playsound call there actually plays the sound, meaning it is played in both places.
TLDR
In both 1.8 and 1.9.4, there is logic to play the pickup sound in two places. However, in 1.8, one of the places it played the sound (when handling the pickup packet) used a method that did nothing (on the client side, which is the only place it would be called in that context). In 1.9.4, both places actually call functional methods, meaning that the sound plays twice.
Fix
The easiest and most logical fix would be to remove the code to play sounds from the handler for the collect item packet. All collectables already make the sound when collected, so it's redundant anyway. As an added benefit, this means that items which are set as silent will not make noise when picked up.
NetHandlerPlayClient.handleCollectItem(SPacketCollectItem) is obfuscated as bkq/a (Lic;)V (bkq.a(ic)). The code that needs to be deleted is on lines 676 through 680.
When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Debug logs
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
Sound recording
I've attached a sound recording of this glitch in action (ItemPlopsGlitch.mp3
). It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
Cause
1.9.4 obfuscation is used in all places where obfuscation is provided; no 1.8 obfuscation is provided right now.
The root cause is that there are two places where picking up an item makes a sound (ignoring /give's code for it). First, EntityItem.onCollideWithPlayer(EntityPlayer) (rr.d(zj)) calls worldObj.playSound (a(DDDLng;Lni;FFZ)). But it also sends a Collect Item packet. When that packet is processed in NetHandlerPlayClient.handleCollectItem (bkq.a(ic), a sound is also played. That duplication causes this issue; the easiest fix is just to remove one of the two (I recommend the one in handleCollectItem - the one on the item pickup side mutes the sound if the item is silent).
But... the same code is present in 1.8 more or less, yet this issue does not occur. Why? Well... let's look at what each version does in both parts.
EntityItem.onCollideWithPlayer
Both have very similar calls in the middle of this method. Compare, though:
1.8if (!this.isSlient()) { this.worldObj.playSoundAtEntity(entityIn, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }1.9.4if (!this.isSilent()) { this.worldObj.playSound((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }Now, the changes here are probably part of some sound engine re-factoring that happened in 1.9 (and probably, the actual method names are the same in the real code). Let's look at the code for these methods:
1.8/** * Plays a sound at the entity's position. Args: entity, sound, volume * (relative to 1.0), and frequency (or pitch, also relative to 1.0). */ public void playSoundAtEntity(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { for (int var5 = 0; var5 < this.worldAccesses.size(); ++var5) { ((IWorldAccess) this.worldAccesses.get(var5)).playSound(p_72956_2_, p_72956_1_.posX, p_72956_1_.posY, p_72956_1_.posZ, p_72956_3_, p_72956_4_); } }1.9.4public void playSound(EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) { for (int i = 0; i < this.eventListeners.size(); ++i) { ((IWorldEventListener)this.eventListeners.get(i)).playSound(player, soundIn, category, x, y, z, volume, pitch); } }More renaming, but the gist is the same. IWorldAccess and IWorldEventListener (ahv) are the same thing, just renamed. There are several implementations. While it isn't entirely clear which is used when, there seems to be one that's used clientside and one that's used serverside (and a path debugging on in 1.9 that isn't important). Here are the implementations:
WorldManager (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { this.mcServer.getConfigurationManager().sendToAllNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionId(), new S29PacketSoundEffect(soundName, x, y, z, volume, pitch)); }RenderGlobal (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { }WorldManager (lr) (1.9.4)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { this.mcServer.getPlayerList().sendToAllNearExcept(player, x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionType().getId(), new SPacketSoundEffect(soundIn, category, x, y, z, volume, pitch)); }RenderGlobal (bnl) (1.8)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { }In both cases, the clientside implementation is empty. Now, the serverside implementation did change between 1.8 and 1.9.4, to exclude sending to a specific player, but in this case the player is null so that change doesn't matter. So, the bug probably isn't in this part of the code.
NetHandlerPlayClient.handleCollectItem
OK, so if the bug isn't on that part, what about NetHandlerPlayClient? Well, both have this logic:
1.8if (var2 != null) { if (var2 instanceof EntityXPOrb) { this.clientWorldController.playSoundAtEntity(var2, "random.orb", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } else { this.clientWorldController.playSoundAtEntity(var2, "random.pop", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, var2, (Entity) var3, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.func_149354_c()); }1.9.4if (entity != null) { if (entity instanceof EntityXPOrb) { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_experience_orb_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } else { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, entity, entitylivingbase, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.getCollectedItemEntityID()); }Very similar, yes? But there's a notable difference... not there, though.
See, in 1.8, clientWorldController.playSoundAtEntity refers to World.playSoundAtEntity. And, as previously shown, that goes through the IWorldAccess es. And the client version, RenderGlobal, does nothing.
But in 1.9.4, that specific playSound method is both defined in World (aht/a (DDDLng;Lni;FFZ)V) and overriden in WorldClient (bks/a (DDDLng;Lni;FFZ)V). The World (aht) implementation does nothing:
World.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { }but WorldClient (bks) does something very direct:
WorldClient.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { double d0 = this.mc.getRenderViewEntity().getDistanceSq(x, y, z); PositionedSoundRecord positionedsoundrecord = new PositionedSoundRecord(soundIn, category, volume, pitch, (float) x, (float) y, (float) z); if (distanceDelay && d0 > 100.0D) { double d1 = Math.sqrt(d0) / 40.0D; this.mc.getSoundHandler().playDelayedSound(positionedsoundrecord, (int) (d1 * 20.0D)); } else { this.mc.getSoundHandler().playSound(positionedsoundrecord); } }Note that, unlike in 1.8, that method actually works. So the playsound call there actually plays the sound, meaning it is played in both places.
TLDR
In both 1.8 and 1.9.4, there is logic to play the pickup sound in two places. However, in 1.8, one of the places it played the sound (when handling the pickup packet) used a method that did nothing (on the client side, which is the only place it would be called in that context). In 1.9.4, both places actually call functional methods, meaning that the sound plays twice.
Fix
The easiest and most logical fix would be to remove the code to play sounds from the handler for the collect item packet. All collectables already make the sound when collected, so it's redundant anyway. As an added benefit, this means that items which are set as silent will not make noise when picked up.
NetHandlerPlayClient.handleCollectItem(SPacketCollectItem) is obfuscated as bkq/a (Lic;)V (bkq.a(ic)). The code that needs to be deleted is on lines 676 through 680.
When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Debug logs
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
Sound recording
I've attached a sound recording of this glitch in action (ItemPlopsGlitch.mp3
). It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
Cause
1.9.4 obfuscation is used in all places where obfuscation is provided; no 1.8 obfuscation is provided right now.
The root cause is that there are two places where picking up an item makes a sound (ignoring /give's code for it). First, EntityItem.onCollideWithPlayer(EntityPlayer) (rr.d(zj)) calls worldObj.playSound (a(DDDLng;Lni;FFZ)). But it also sends a Collect Item packet. When that packet is processed in NetHandlerPlayClient.handleCollectItem (bkq.a(ic), a sound is also played. That duplication causes this issue; the easiest fix is just to remove one of the two (I recommend the one in handleCollectItem - the one on the item pickup side mutes the sound if the item is silent).
But... the same code is present in 1.8 more or less, yet this issue does not occur. Why? Well... let's look at what each version does in both parts.
EntityItem.onCollideWithPlayer
Both have very similar calls in the middle of this method. Compare, though:
1.8if (!this.isSlient()) { this.worldObj.playSoundAtEntity(entityIn, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }1.9.4if (!this.isSilent()) { this.worldObj.playSound((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }Now, the changes here are probably part of some sound engine re-factoring that happened in 1.9 (and probably, the actual method names are the same in the real code). Let's look at the code for these methods:
1.8/** * Plays a sound at the entity's position. Args: entity, sound, volume * (relative to 1.0), and frequency (or pitch, also relative to 1.0). */ public void playSoundAtEntity(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { for (int var5 = 0; var5 < this.worldAccesses.size(); ++var5) { ((IWorldAccess) this.worldAccesses.get(var5)).playSound(p_72956_2_, p_72956_1_.posX, p_72956_1_.posY, p_72956_1_.posZ, p_72956_3_, p_72956_4_); } }1.9.4public void playSound(EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) { for (int i = 0; i < this.eventListeners.size(); ++i) { ((IWorldEventListener)this.eventListeners.get(i)).playSound(player, soundIn, category, x, y, z, volume, pitch); } }More renaming, but the gist is the same. IWorldAccess and IWorldEventListener (ahv) are the same thing, just renamed. There are several implementations. While it isn't entirely clear which is used when, there seems to be one that's used clientside and one that's used serverside (and a path debugging on in 1.9 that isn't important). Here are the implementations:
WorldManager (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { this.mcServer.getConfigurationManager().sendToAllNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionId(), new S29PacketSoundEffect(soundName, x, y, z, volume, pitch)); }RenderGlobal (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { }WorldManager (lr) (1.9.4)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { this.mcServer.getPlayerList().sendToAllNearExcept(player, x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionType().getId(), new SPacketSoundEffect(soundIn, category, x, y, z, volume, pitch)); }RenderGlobal (bnl) (1.8)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { }In both cases, the clientside implementation is empty. Now, the serverside implementation did change between 1.8 and 1.9.4, to exclude sending to a specific player, but in this case the player is null so that change doesn't matter. So, the bug probably isn't in this part of the code.
NetHandlerPlayClient.handleCollectItem
OK, so if the bug isn't on that part, what about NetHandlerPlayClient? Well, both have this logic:
1.8if (var2 != null) { if (var2 instanceof EntityXPOrb) { this.clientWorldController.playSoundAtEntity(var2, "random.orb", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } else { this.clientWorldController.playSoundAtEntity(var2, "random.pop", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, var2, (Entity) var3, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.func_149354_c()); }1.9.4if (entity != null) { if (entity instanceof EntityXPOrb) { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_experience_orb_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } else { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, entity, entitylivingbase, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.getCollectedItemEntityID()); }Very similar, yes? But there's a notable difference... not there, though.
See, in 1.8, clientWorldController.playSoundAtEntity refers to World.playSoundAtEntity. And, as previously shown, that goes through the IWorldAccess es. And the client version, RenderGlobal, does nothing.
But in 1.9.4, that specific playSound method is both defined in World (aht/a (DDDLng;Lni;FFZ)V) and overriden in WorldClient (bks/a (DDDLng;Lni;FFZ)V). The World (aht) implementation does nothing:
World.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { }but WorldClient (bks) does something very direct:
WorldClient.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { double d0 = this.mc.getRenderViewEntity().getDistanceSq(x, y, z); PositionedSoundRecord positionedsoundrecord = new PositionedSoundRecord(soundIn, category, volume, pitch, (float) x, (float) y, (float) z); if (distanceDelay && d0 > 100.0D) { double d1 = Math.sqrt(d0) / 40.0D; this.mc.getSoundHandler().playDelayedSound(positionedsoundrecord, (int) (d1 * 20.0D)); } else { this.mc.getSoundHandler().playSound(positionedsoundrecord); } }Note that, unlike in 1.8, that method actually works. So the playsound call there actually plays the sound, meaning it is played in both places.
TLDR
In both 1.8 and 1.9.4, there is logic to play the pickup sound in two places. However, in 1.8, one of the places it played the sound (when handling the pickup packet) used a method that did nothing (on the client side, which is the only place it would be called in that context). In 1.9.4, both places actually call functional methods, meaning that the sound plays twice.
Fix
The easiest and most logical fix would be to remove the code to play sounds from the handler for the collect item packet. All collectables already make the sound when collected, so it's redundant anyway. As an added benefit, this means that items which are set as silent will not make noise when picked up.
NetHandlerPlayClient.handleCollectItem(SPacketCollectItem) is obfuscated as bkq/a (Lic;)V (bkq.a(ic)). The code that needs to be deleted is on lines 676 through 680.
When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Debug logs
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
Sound recording
I've attached a sound recording of this glitch in action (ItemPlopsGlitch.mp3
). It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
Cause
1.9.4 obfuscation is used in all places where obfuscation is provided; no 1.8 obfuscation is provided right now.
The root cause is that there are two places where picking up an item makes a sound (ignoring /give's code for it). First, EntityItem.onCollideWithPlayer(EntityPlayer) (rr.d(zj)) calls worldObj.playSound (a(DDDLng;Lni;FFZ)). But it also sends a Collect Item packet. When that packet is processed in NetHandlerPlayClient.handleCollectItem (bkq.a(ic), a sound is also played. That duplication causes this issue; the easiest fix is just to remove one of the two (I recommend the one in handleCollectItem - the one on the item pickup side mutes the sound if the item is silent).
But... the same code is present in 1.8 more or less, yet this issue does not occur. Why? Well... let's look at what each version does in both parts.
EntityItem.onCollideWithPlayer
Both have very similar calls in the middle of this method. Compare, though:
1.8if (!this.isSlient()) { this.worldObj.playSoundAtEntity(entityIn, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }1.9.4if (!this.isSilent()) { this.worldObj.playSound((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }Now, the changes here are probably part of some sound engine re-factoring that happened in 1.9 (and probably, the actual method names are the same in the real code). Let's look at the code for these methods:
1.8/** * Plays a sound at the entity's position. Args: entity, sound, volume * (relative to 1.0), and frequency (or pitch, also relative to 1.0). */ public void playSoundAtEntity(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { for (int var5 = 0; var5 < this.worldAccesses.size(); ++var5) { ((IWorldAccess) this.worldAccesses.get(var5)).playSound(p_72956_2_, p_72956_1_.posX, p_72956_1_.posY, p_72956_1_.posZ, p_72956_3_, p_72956_4_); } }1.9.4public void playSound(EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) { for (int i = 0; i < this.eventListeners.size(); ++i) { ((IWorldEventListener)this.eventListeners.get(i)).playSound(player, soundIn, category, x, y, z, volume, pitch); } }More renaming, but the gist is the same. IWorldAccess and IWorldEventListener (ahv) are the same thing, just renamed. There are several implementations. While it isn't entirely clear which is used when, there seems to be one that's used clientside and one that's used serverside (and a path debugging on in 1.9 that isn't important). Here are the implementations:
WorldManager (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { this.mcServer.getConfigurationManager().sendToAllNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionId(), new S29PacketSoundEffect(soundName, x, y, z, volume, pitch)); }RenderGlobal (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { }WorldManager (lr) (1.9.4)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { this.mcServer.getPlayerList().sendToAllNearExcept(player, x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionType().getId(), new SPacketSoundEffect(soundIn, category, x, y, z, volume, pitch)); }RenderGlobal (bnl) (1.8)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { }In both cases, the clientside implementation is empty. Now, the serverside implementation did change between 1.8 and 1.9.4, to exclude sending to a specific player, but in this case the player is null so that change doesn't matter. So, the bug probably isn't in this part of the code.
NetHandlerPlayClient.handleCollectItem
OK, so if the bug isn't on that part, what about NetHandlerPlayClient? Well, both have this logic:
1.8if (var2 != null) { if (var2 instanceof EntityXPOrb) { this.clientWorldController.playSoundAtEntity(var2, "random.orb", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } else { this.clientWorldController.playSoundAtEntity(var2, "random.pop", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, var2, (Entity) var3, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.func_149354_c()); }1.9.4if (entity != null) { if (entity instanceof EntityXPOrb) { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_experience_orb_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } else { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, entity, entitylivingbase, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.getCollectedItemEntityID()); }Very similar, yes? But there's a notable difference... not there, though.
See, in 1.8, clientWorldController.playSoundAtEntity refers to World.playSoundAtEntity. And, as previously shown, that goes through the IWorldAccess es. And the client version, RenderGlobal, does nothing.
But in 1.9.4, that specific playSound method is both defined in World (aht/a (DDDLng;Lni;FFZ)V) and overriden in WorldClient (bks/a (DDDLng;Lni;FFZ)V). The World (aht) implementation does nothing:
World.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { }but WorldClient (bks) does something very direct:
WorldClient.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { double d0 = this.mc.getRenderViewEntity().getDistanceSq(x, y, z); PositionedSoundRecord positionedsoundrecord = new PositionedSoundRecord(soundIn, category, volume, pitch, (float) x, (float) y, (float) z); if (distanceDelay && d0 > 100.0D) { double d1 = Math.sqrt(d0) / 40.0D; this.mc.getSoundHandler().playDelayedSound(positionedsoundrecord, (int) (d1 * 20.0D)); } else { this.mc.getSoundHandler().playSound(positionedsoundrecord); } }Note that, unlike in 1.8, that method actually works. So the playsound call there actually plays the sound, meaning it is played in both places.
TLDR
In both 1.8 and 1.9.4, there is logic to play the pickup sound in two places. However, in 1.8, one of the places it played the sound (when handling the pickup packet) used a method that did nothing (on the client side, which is the only place it would be called in that context). In 1.9.4, both places actually call functional methods, meaning that the sound plays twice.
Fix
The easiest and most logical fix would be to remove the code to play sounds from the handler for the collect item packet. All collectables already make the sound when collected, so it's redundant anyway. As an added benefit, this means that items which are set as silent will not make noise when picked up.
NetHandlerPlayClient.handleCollectItem(SPacketCollectItem) is obfuscated as bkq/a (Lic;)V (bkq.a(ic)). The code that needs to be deleted is on lines 676 through 680.
When picking up an item, the "Item plops" sound plays twice at the same time. It's subtle, but you can hear a slightly different pitch sometimes (but not all of the time; sometimes the two sound the same). This is minor but slightly irritating.
To reproduce, simply toss an item on the ground and then pick it up again. You should here a slightly different sound than was heard in previous versions since it's actually two sounds at once; if not, try tossing it and picking it up again as there is a randomness factor to it.
Fix
The easiest and most logical fix would be to remove the code to play sounds from the handler for the collect item packet. All collectables already make the sound when collected, so it's redundant anyway. As an added benefit, this means that items which are set as silent will not make noise when picked up.
NetHandlerPlayClient.handleCollectItem(SPacketCollectItem) is obfuscated as bkq/a (Lic;)V (bkq.a(ic)). The code that needs to be deleted is on lines 676 through 680.
Debug logs
Here's a clearer debug log (see the wiki.vg debugging article for more info; this is the config I used):
[14:22:37.828] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e [14:22:37.829] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 [14:22:38.784] [Client thread/DEBUG]: Removed channel 98ab48ca-89b5-4738-a9dd-6f53becd9b0e because it's not playing anymore [14:22:38.784] [Client thread/DEBUG]: Removed channel 07f2cf7b-bbc8-4a8b-867a-5cc7aab846c2 because it's not playing anymore [14:22:41.199] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 [14:22:41.200] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel f99181c0-ddff-47e7-91c0-f8f786f0b818 [14:22:42.156] [Client thread/DEBUG]: Removed channel f99181c0-ddff-47e7-91c0-f8f786f0b818 because it's not playing anymore [14:22:42.157] [Client thread/DEBUG]: Removed channel 11b01991-2c8b-4312-8e10-efb90c2b6e85 because it's not playing anymore [14:22:44.837] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 [14:22:44.839] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e482c318-7d70-4a6c-bda9-56eccdb277a1 [14:22:45.794] [Client thread/DEBUG]: Removed channel e482c318-7d70-4a6c-bda9-56eccdb277a1 because it's not playing anymore [14:22:45.794] [Client thread/DEBUG]: Removed channel d0f9499d-1bb2-4d66-b810-94288b9f23f4 because it's not playing anymore [14:22:47.824] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 [14:22:47.826] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 [14:22:48.797] [Client thread/DEBUG]: Removed channel d43b6f6e-78cc-40d2-8124-ee2ab8e1d084 because it's not playing anymore [14:22:48.797] [Client thread/DEBUG]: Removed channel eaf20e49-3083-4cc1-8c96-ce431dfe7947 because it's not playing anymoreNote that for each item, there are two "Playing sound" entries at nearly the same time.
This does not happen with /playsound. It only happens when items on the ground are picked up.
Here's a snippet from the debug log when using /playsound (the bug is not seen here):
[14:22:50.478] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:50.495] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e69b8134-1fea-40a3-b443-578a8985a080 [14:22:50.496] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:51.434] [Client thread/DEBUG]: Removed channel e69b8134-1fea-40a3-b443-578a8985a080 because it's not playing anymore [14:22:52.380] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:52.389] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel e789c734-5dd4-4e03-823c-985602b42f3f [14:22:52.391] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:53.337] [Client thread/DEBUG]: Removed channel e789c734-5dd4-4e03-823c-985602b42f3f because it's not playing anymore [14:22:54.229] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:54.232] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 [14:22:54.233] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:55.188] [Client thread/DEBUG]: Removed channel 62e364c0-faeb-4c00-bfde-c9eafba22e36 because it's not playing anymore [14:22:56.178] [Server thread/INFO]: [pokechu22: Played sound 'minecraft:entity.item.pickup' to pokechu22] [14:22:56.219] [Client thread/DEBUG]: Playing sound minecraft:random/pop for event minecraft:sounds/random/pop.ogg as channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 [14:22:56.219] [Client thread/INFO]: [CHAT] Played sound 'minecraft:entity.item.pickup' to pokechu22 [14:22:57.192] [Client thread/DEBUG]: Removed channel c443fbe0-02e4-4b9d-8a25-31ba50ab7820 because it's not playing anymoreNote that in this log, there is only one "Playing sound" entry per sound.
Sound recording
I've attached a sound recording of this glitch in action (ItemPlopsGlitch.mp3
). It corresponds with the above logs: 4 picking up items normally followed by 4 /playsound usages.
Cause
1.9.4 obfuscation is used in all places where obfuscation is provided; no 1.8 obfuscation is provided right now.
The root cause is that there are two places where picking up an item makes a sound (ignoring /give's code for it). First, EntityItem.onCollideWithPlayer(EntityPlayer) (rr.d(zj)) calls worldObj.playSound (a(DDDLng;Lni;FFZ)). But it also sends a Collect Item packet. When that packet is processed in NetHandlerPlayClient.handleCollectItem (bkq.a(ic), a sound is also played. That duplication causes this issue; the easiest fix is just to remove one of the two (I recommend the one in handleCollectItem - the one on the item pickup side mutes the sound if the item is silent).
But... the same code is present in 1.8 more or less, yet this issue does not occur. Why? Well... let's look at what each version does in both parts.
NOTE THAT THE CODE AFTER THIS IS ONLY TO EXPLAIN WHY THIS DID NOT HAPPEN IN 1.8 DESPITE THE REDUNDANT CODE STILL EXISTING. THE ACTUAL BUG IS AN EASY FIX.
EntityItem.onCollideWithPlayer
Both have very similar calls in the middle of this method. Compare, though:
1.8if (!this.isSlient()) { this.worldObj.playSoundAtEntity(entityIn, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }1.9.4if (!this.isSilent()) { this.worldObj.playSound((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); }Now, the changes here are probably part of some sound engine re-factoring that happened in 1.9 (and probably, the actual method names are the same in the real code). Let's look at the code for these methods:
1.8/** * Plays a sound at the entity's position. Args: entity, sound, volume * (relative to 1.0), and frequency (or pitch, also relative to 1.0). */ public void playSoundAtEntity(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { for (int var5 = 0; var5 < this.worldAccesses.size(); ++var5) { ((IWorldAccess) this.worldAccesses.get(var5)).playSound(p_72956_2_, p_72956_1_.posX, p_72956_1_.posY, p_72956_1_.posZ, p_72956_3_, p_72956_4_); } }1.9.4public void playSound(EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) { for (int i = 0; i < this.eventListeners.size(); ++i) { ((IWorldEventListener)this.eventListeners.get(i)).playSound(player, soundIn, category, x, y, z, volume, pitch); } }More renaming, but the gist is the same. IWorldAccess and IWorldEventListener (ahv) are the same thing, just renamed. There are several implementations. While it isn't entirely clear which is used when, there seems to be one that's used clientside and one that's used serverside (and a path debugging on in 1.9 that isn't important). Here are the implementations:
WorldManager (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { this.mcServer.getConfigurationManager().sendToAllNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionId(), new S29PacketSoundEffect(soundName, x, y, z, volume, pitch)); }RenderGlobal (1.8)/** * Plays the specified sound. Arg: soundName, x, y, z, volume, pitch */ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) { }WorldManager (lr) (1.9.4)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { this.mcServer.getPlayerList().sendToAllNearExcept(player, x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.theWorldServer.provider.getDimensionType().getId(), new SPacketSoundEffect(soundIn, category, x, y, z, volume, pitch)); }RenderGlobal (bnl) (1.8)public void playSound(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) { }In both cases, the clientside implementation is empty. Now, the serverside implementation did change between 1.8 and 1.9.4, to exclude sending to a specific player, but in this case the player is null so that change doesn't matter. So, the bug probably isn't in this part of the code.
NetHandlerPlayClient.handleCollectItem
OK, so if the bug isn't on that part, what about NetHandlerPlayClient? Well, both have this logic:
1.8if (var2 != null) { if (var2 instanceof EntityXPOrb) { this.clientWorldController.playSoundAtEntity(var2, "random.orb", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } else { this.clientWorldController.playSoundAtEntity(var2, "random.pop", 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, var2, (Entity) var3, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.func_149354_c()); }1.9.4if (entity != null) { if (entity instanceof EntityXPOrb) { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_experience_orb_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } else { this.clientWorldController.playSound(entity.posX, entity.posY, entity.posZ, SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((this.avRandomizer.nextFloat() - this.avRandomizer.nextFloat()) * 0.7F + 1.0F) * 2.0F, false); } this.gameController.effectRenderer.addEffect(new EntityPickupFX(this.clientWorldController, entity, entitylivingbase, 0.5F)); this.clientWorldController.removeEntityFromWorld(packetIn.getCollectedItemEntityID()); }Very similar, yes? But there's a notable difference... not there, though.
See, in 1.8, clientWorldController.playSoundAtEntity refers to World.playSoundAtEntity. And, as previously shown, that goes through the IWorldAccess es. And the client version, RenderGlobal, does nothing.
But in 1.9.4, that specific playSound method is both defined in World (aht/a (DDDLng;Lni;FFZ)V) and overriden in WorldClient (bks/a (DDDLng;Lni;FFZ)V). The World (aht) implementation does nothing:
World.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { }but WorldClient (bks) does something very direct:
WorldClient.playSound (1.9.4)public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) { double d0 = this.mc.getRenderViewEntity().getDistanceSq(x, y, z); PositionedSoundRecord positionedsoundrecord = new PositionedSoundRecord(soundIn, category, volume, pitch, (float) x, (float) y, (float) z); if (distanceDelay && d0 > 100.0D) { double d1 = Math.sqrt(d0) / 40.0D; this.mc.getSoundHandler().playDelayedSound(positionedsoundrecord, (int) (d1 * 20.0D)); } else { this.mc.getSoundHandler().playSound(positionedsoundrecord); } }Note that, unlike in 1.8, that method actually works. So the playsound call there actually plays the sound, meaning it is played in both places.
TLDR
In both 1.8 and 1.9.4, there is logic to play the pickup sound in two places. However, in 1.8, one of the places it played the sound (when handling the pickup packet) used a method that did nothing (on the client side, which is the only place it would be called in that context). In 1.9.4, both places actually call functional methods, meaning that the sound plays twice.
This is as much of a bug as quasiconnectivity. (AS IN NOT ALL BUG)
The behavior shown in that video is definitely a bug, but dispensers and droppers should still fire on red stone updates. This way, you can make it so that you change a dispenser to be dual-edge, but also not effect anything else. (If you think it will effect something, I'd like to know). But the current fix breaks a ton of stuff. Top of the list: Hyperspawners.
The bug
Currently, when teleporting a player (either relatively or absolutely) the motion of the teleport is visible sometimes, but not always. This behaviour is inconsistent even at 60fps.
How to reproduce
- Make two identical buildings 16 blocks apart from each other on the worlds X axis
- Keep executing the following two commands
/tp ~16 ~ ~
/tp ~-16 ~ ~
→ Note the occasional flash in between the teleports
Results
When a teleportation occurs, a flash is sometimes seen. Sometimes blocks even disappear until you move your mouse.
This flash is caused by extra frames generated during the teleportation. Causing an image to be rendered from the position in between the start position and the destination. The disappearing blocks is a different issue that deserves its own ticket.
Expected
To either not see a flash at all, or see it all the time (at 60fps).
Possible fix
It appears that this happens because only one of the two previous position fields is updated when teleporting. Specifically, setPositionAndRotation updates prevPosX/Y/Z, but leaves lastTickX/Y/Z alone. Both of these fields are used to interpolate position (each in different contexts), and only using one causes this bug. (Side note: I'm not entirely sure why there are two fields that have more or less the same purpose - perhaps they can be merged).
This is my ([Mod] Pokechu22) fix (in NetHandlerPlayClient.handlePlayerPosLook):
EntityPlayer player = this.gameController.player; double x = packetIn.getX(); double y = packetIn.getY(); double z = packetIn.getZ(); float yaw = packetIn.getYaw(); float pitch = packetIn.getPitch(); if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.X)) { player.lastTickPosX += x; player.chasingPosX += x; player.prevChasingPosX += x; x += player.posX; } else { player.lastTickPosX = x; player.chasingPosX = x; player.prevChasingPosX = x; player.motionX = 0.0D; } if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.Y)) { player.lastTickPosY += y; player.chasingPosY += y; player.prevChasingPosY += y; y += player.posY; } else { player.lastTickPosY = y; player.chasingPosY = y; player.prevChasingPosY = y; player.motionY = 0.0D; } if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.Z)) { player.lastTickPosZ += z; player.chasingPosZ += z; player.prevChasingPosZ += z; z += player.posZ; } else { player.lastTickPosZ = z; player.chasingPosZ = z; player.prevChasingPosZ = z; player.motionZ = 0.0D; }
I update lastTickPosX/Y/Z by the delta if it is a relative teleport, and set it directly if it is an absolute teleport. Changing it by the delta is important - if we just set it to the new position, then there actually is a (subtle) pause as the camera stays in the new position for the entire tick rather than moving between the offset old position and the new position.
I also update prevChasingPos/chasingPosX/Y/Z, which are used to render capes. This keeps capes from spazing out when teleporting (but isn't too important to the core problem).
I don't touch prevPosX/Y/Z at all in this code, simply because any changes made would be overwritten by the call to setPositionAndRotation. It may be better to also adjust prevPosX/Y/Z by the delta, but I couldn't detect a significant difference and that would require tweaking setPositionAndRotation.
(note that MC-120545 needs to also be fixed for seamless teleporting)
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 [Mod] 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.
The bug
When the player attacks a blaze, nearby blazes behind solid walls will turn hostile and shoot at the player as if the wall wasn't there. Those blazes also continue to attack when the player has switched to Creative mode, whereas all blazes that initially had line-of-sight to the player will stop attacking.
Code analysis
The following analysis is based on a decompiled version of Minecraft using MCP 9.40pre-1 with MC 1.12.2 mappings (guide by [Mod] Pokechu22 here)
As per net.minecraft.entity.monster.EntityBlaze.initEntityAI(), a blaze's entityCallsForHelp boolean in the net.minecraft.entity.ai.EntityAIHurtByTarget class is always set to true, which means that it will alert other blaze entities within its followRange as soon as it gets attacked. The method which is called when a blaze wants to alert their fellow blazes is net.minecraft.entity.ai.EntityAIHurtByTarget.alertOthers().
This method, however, does not check if there are any blocks in between the attacking entity and the alerted blaze. So, I quickly made a hacky for-loop to check if there are any blocks other than air in between the entities' coordinates. Albeit I absolutely do not recommend to use this code as it is wacky as hell and does not consider all blocks within the view of the alerted blaze, it does a decent job in showing what the issue is – so I'll post it here anyway if anyone wants to test this.
The bug
When activated (by clicking or walking on top of it), redstone ore not placed at y=0 produces particles on all sides except for its underside. If placed at y=0, particles will appear on the underside of the block as expected.
Code analysis
Code analysis by [Mod] Pokechu22 can be found in this Reddit comment.
Here's the code in BlockRedstoneOre:
private void spawnParticles(World worldIn, BlockPos pos) { Random random = worldIn.rand; double d0 = 0.0625D; for (int i = 0; i < 6; ++i) { double d1 = (double)((float)pos.getX() + random.nextFloat()); double d2 = (double)((float)pos.getY() + random.nextFloat()); double d3 = (double)((float)pos.getZ() + random.nextFloat()); if (i == 0 && !worldIn.getBlockState(pos.up()).isOpaqueCube()) { d2 = (double)pos.getY() + 0.0625D + 1.0D; } if (i == 1 && !worldIn.getBlockState(pos.down()).isOpaqueCube()) { d2 = (double)pos.getY() - 0.0625D; } if (i == 2 && !worldIn.getBlockState(pos.south()).isOpaqueCube()) { d3 = (double)pos.getZ() + 0.0625D + 1.0D; } if (i == 3 && !worldIn.getBlockState(pos.north()).isOpaqueCube()) { d3 = (double)pos.getZ() - 0.0625D; } if (i == 4 && !worldIn.getBlockState(pos.east()).isOpaqueCube()) { d1 = (double)pos.getX() + 0.0625D + 1.0D; } if (i == 5 && !worldIn.getBlockState(pos.west()).isOpaqueCube()) { d1 = (double)pos.getX() - 0.0625D; } if (d1 < (double)pos.getX() || d1 > (double)(pos.getX() + 1) || d2 < 0.0D || d2 > (double)(pos.getY() + 1) || d3 < (double)pos.getZ() || d3 > (double)(pos.getZ() + 1)) { worldIn.spawnParticle(EnumParticleTypes.REDSTONE, d1, d2, d3, 0.0D, 0.0D, 0.0D); } } }It checks 6 sides, including down, and then checks to make sure it's not rendering inside of the block. But for checking on y, it does d2 < 0.0D || d2 > (double)(pos.getY() + 1) instead of d2 < (double)pos.getY() || d2 > (double)(pos.getY() + 1) — that looks like a mistake to me.
@[Mod] Pokechu22: I meant it may take some time until all the generated chunks are flushed from memory to disk. Maybe the process of serializing the chunks takes a lot of more time than generating them.
@[Mod] Pokechu22 MC-72943 seems to be it. Thank you for linking it ![]()
[Mod] Pokechu22: Being tracked in MC-91093.
Mobs that normally react to sunlight will catch on fire in the end if there is no block above them and sufficient light at their head. This effects:
- Zombies (and subclasses)
- Skeletons (and subclasses)
- Endermen (but note that the lighting has to be at head level; a torch at ground level does not produce enough light). Also note that the behavior of enderman is to randomly teleport when in sun, not to catch on fire; endermen lit in this way will teleport but unlit ones will not.
Might relate to:
- MC-47365

Code analysis ([Mod] Pokechu22):
The code that's responsible for mobs catching on fire hasn't any major logic changes since the mechanic was introduced (introduced Februrary 14th 2010 indev; it did change on February 18, 2010 indev but hasn't changed in a significant way since). Here is the logic for each entity:
public void onLivingUpdate() { if (this.world.isDaytime() && !this.world.isRemote) { float f = this.getBrightness(); BlockPos blockpos = this.getRidingEntity() instanceof EntityBoat ? (new BlockPos(this.posX, (double)Math.round(this.posY), this.posZ)).up() : new BlockPos(this.posX, (double)Math.round(this.posY), this.posZ); if (f > 0.5F && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.world.canSeeSky(blockpos)) { boolean flag = true; // Snip: logic to set flag to false if wearing a helmet if (flag) { this.setFire(8); } } } super.onLivingUpdate(); }
public void onLivingUpdate() { if (this.world.isDaytime() && !this.world.isRemote && !this.isChild() && this.shouldBurnInDay()) { float f = this.getBrightness(); if (f > 0.5F && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.world.canSeeSky(new BlockPos(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ))) { boolean flag = true; // Snip: logic to set flag to false if wearing a helmet if (flag) { this.setFire(8); } } } super.onLivingUpdate(); }
Note how in all cases it:
- Checks if world.isDayTime
- Checks the brightness of the monster and compares it to .5 (this corresponds to light level 11, I think)
- Checks whether the block can see the sky (this is a heightmap check, not effected by e.g. glass)
- Does some RNG stuff
The brightness of the monster is computed by the max of the skylight (minus a factor) and block light. So, it can be above .5 even without sunlight if the monster is right next to a light source. Heightmap information is correct (the heightmap debug renderer can be used to verify this). So, that leaves only world.isDayTime.
This method might have an incorrect name due to MCP, or it might be named similarly in the actual codebase; all it does is check whether skylightSubtracted (the previously noted skylight offset factor) is less than 4. The logic responsible for setting that variable is somewhat convoluted (MCP method is World.calculateSkylightSubtracted) but a key factor is the "celestial angle"; for the overworld this is a calculation of the position of the sun (I think) but the nether hardcodes it to return .5 always, and the end has it always return 0. This actually causes the end to be considered daytime (0 and 1 are high noon, and .5 is midnight).
Basically, for some reason, the end is considered as being in daylight and thus mobs can burn. However, to me, it seems wrong that the code checks if it is day and then how bright the monster is to determine if they're exposed to sunlight; it would make much more sense to only check the sunlight value (modified by skylightSubtracted) and use that to check whether they are exposed. That may not have been possible in indev, but it is now...
The bug
When a player in spectator mode right clicks a container entity (currently only MinecartChest and HopperMinecart) the "Unable to open. Loot not generated yet." message is printed twice.
Note: This message has also one space too much at the end.
How to reproduce with MCP (1.11+) (easy)
- Locate net.minecraft.entity.player.EntityPlayerMP.displayGUIChest(IInventory chestInventory).
- Change the true in the following line to false.
this.addChatComponentMessage((new TextComponentTranslation("container.spectatorCantOpen", new Object[0])).setStyle((new Style()).setColor(TextFormatting.RED)), true); - Start Minecraft
- Summon for example a MinecartChest
/summon chest_minecart ~ ~ ~ {LootTable:"chests/simple_dungeon"} - Switch to Spectator mode
- Right-click the MinecartChest
How to reproduce (1.11+) (advanced)
Note: The following steps will cause the original version folder to be deteled
- Open the %appdata%\.minecraft\versions directory
- Copy the folder of the latest version and rename the copied folder to "
MC-94682" - Open the copied folder and apply [Mod] Pokechu22's modification (requires Python)
- Rename the .jar file to "
MC-94682" - Open the .json file in the copied folder with a text editor
- Set "
MC-94682" as id - Remove the contents of the downloads key at the end of the the file
- Set "
- Start Minecraft
- Select the version called "
MC-94682" - Summon for example a MinecartChest
/summon chest_minecart ~ ~ ~ {LootTable:"chests/simple_dungeon"} - Switch to Spectator mode
- Right-click the MinecartChest
Delete the folder of the version you modified again and rename the copy to the original name
The reason
The following is based on a decompiled version of Minecraft 1.9 using MCP 9.24 beta.
The reason why this happens is because the method net.minecraft.client.multiplayer.PlayerControllerMP.func_187097_a(EntityPlayer, Entity, ItemStack, EnumHand) returns EnumActionResult.PASS for players in spectator mode. Because of this the player right clicks with his main- and offhand on the entity. This could be solved by having the method net.minecraft.client.Minecraft.rightClickMouse() in general run only for the mainhand if the player is in spectator mode.
I don't seem to be able to use
{Effect:[{Id:23, [...] }]}
on an AreaEffectCloud - it simply gives no effects and everything else works perfectly.
Exact command I'm using:
/summon area_effect_cloud ~ ~ ~ {Particle:mobSpell,ReapplicationDelay:10,Radius:2.5f,RadiusPerTick:-0.0025f,RadiusOnUse:-0.05f,Duration:1000,DurationOnUse:0f,WaitTime:0,Effects:[{Id:23,Amplifier:2,Duration:600,ShowParticles:0b}],Potion:"minecraft:water"}
What I expected to happen:
Saturation effect applied to player
What actually happened was:
No effect was applied
Steps to Reproduce:
1. Put the command above in a command block
2. Activate the command block
3. Stand in cloud; no effect is applied
Code analysis by [Mod] Pokechu22 can be found in this comment.
The bug
The anti-cheat engine is being over-zealous causing the following issues with nether portals, caused by the game teleporting a player back:
- Portals setting the player on fire if there is lava at the exact location of the entry portal in the other dimension.
MC-97523- Can kill player if they are low on food or health - very serious.
- Deals 11 damage (5 1/2 hearts) over time.
- Usually survivable in survival mode, especially if you are full on food or have good armour - you will only take 1 or 2 hearts' damage.
- Portals loading chunks at the exact location of the entry portal, but in the other dimension.
MC-97523- Only the chunk at the exact location of the other dimension's portal loads.
- Only the terrain is generated: entities do not spawn.
- InhabitedTime of that chunk is 0.
These issues are usually characterised by a debug message in the chat claiming that the player moved too quickly:
[11:07:36] [Server thread/WARN]: FM22 moved too quickly! 8740.213380243677,-16.0,8751.561382695907
(this was going through a nether portal in the overworld at 10 000, 10 000).
Workaround
Remove all fire/lava at the exact location of the entry portal in the other dimension. E.g., if you have a portal at (100, 64, 100) in the overworld and you are set on fire when going to the nether, go to (100, 64, 100) in the nether (not to the location of the exit portal) and remove fire and lava around that exact location.
Related issues
MC-90062 - which covers the other effects of the cheat engine changes
MC-86850 - which covers how taking certain actions may cause you to remain at the erroneous location.
The fix
A suggested fix by Xcom6000, Timothy Miller, and [Mod] Pokechu22 can be found in this comment.
Note
The following is based on a decompiled version of Minecraft 1.9 using MCP 9.24 beta.
The bug
The field net.minecraft.block.BlockRedstoneTorch.toggles is a map with Worlds (like Overworld, End and Nether) as key and a list of redstone torch states as value. The problem is that a world is never removed from this list, which means that all save files you load containing redstone torches that burned out have still a reference in this list and cannot be collected by the garbage collection.
In general it might be better to use a TileEntity to store this value. But I am not too familiar with what effect this would have on performance.
[Mod] Pokechu22: Alternatively, using a WeakHashMap would also solve this, as it would allow the World to be collected without having to do any extra work.
The bug
Since farmland is now 15/16 of a block, jumping on it will change it back to dirt, which is a full block. The player is now stuck inside the block.
Caused by fixing MC-85162.
Code analysis / Fix
See this comment by [Mod] Pokechu22.
[Mod] Pokechu22, this limitation is indeed strange because it applies to Creative mode as well and there you have an unlimited amount of items anyways.
Sorry, yes you are right. I thought they acted the same way iron doors or trapdoors act.
Mods please do not close this report as a duplicate because then we have an unnecessary discussion about whether or not it is WAI and like [Mod] Pokechu22 said it is definitely not.
I would suggest fixing it by having client and server call the method net.minecraft.item.ItemLead.attachToFence(EntityPlayer, World, BlockPos) but change this method to only create the LeashKnot and leash the entity server-side.
Note: The method net.minecraft.item.ItemLead.onItemUse(ItemStack, EntityPlayer, World, BlockPos, EnumHand, EnumFacing, float, float, float) contains kind of dead code because if the player successfully interacts with a block it will not use the item. If the player fails right clicking while holding a leash, this method will fail as well.
[Mod] Pokechu22, I assumed as well that the initiateShutdown method is the cause. Please link from the description to your comment.
[Mod] Pokechu22, it's MC-58812
When a world is generated or loaded, stray chunks are being generated at the wrong coordinates. This is seen as stray region files with unexpectedly large coordinates. These stray chunks appear to have coordinates that are 16 times what is expected. The terrain at these chunks appears to be the correct terrain for that location - but the chunk itself should not be generating.
This is fairly easy to reproduce because the stray chunks seem to appear fairly consistently in the same locations. For example, create a world with the seed -7374548781075652015. This will generate region files r.0.0.mca and r-1.0.mca as expected, but it will also generate stray region files r.5.13.mca and r.6.8.mca. These stray region files will have single chunks in them at 2560, 6656 and 3072, 4352. Note that these coordinates are all multiples of 256. This suggests that chunk coordinates are being multiplied by 16 twice.
Moving around will sometimes generate additional stray region files, again at fairly predictable coordinates. Movement can be by walking or teleporting; it seems to make no difference.
Code analysis by [Mod] Pokechu22 in this comment.
In the method which logs "ThreadedAnvilChunkStorage ({}): All chunks are saved", a single element attempts to be popped from a Map.
The problem is that between checking for an element in this Map and the element being popped, if /save-all flush is executed, there is a chance that it will be popped and removed by another thread, causing the map to be empty, and the save thread to crash.
Everything from this point down is from research by [Mod] Pokechu22.
Actually encountering this on a real server is very rare (it took me 600 tries with a bot and I've reproduced it randomly a few other times out of a bunch of other times I've run /save-all flush (all to test this bug)), but it does eventually happen. See crash-2016-09-08_20.10.34-server.txt
and crash-2016-09-08_20.10.32-server.txt
(which, oddly, were generated at roughly the same time - I've never seen the watchdog do that with other crashes. I'm pretty sure that 20.10.34 has the actual relevant stacktrace, though) Also, here's the very end of the log:
[20:10:25] [Server thread/INFO]: ThreadedAnvilChunkStorage (world): All chunks are saved [20:10:25] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM-1): All chunks are saved [20:10:25] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM1): All chunks are saved [20:10:25] [Server thread/INFO]: [TestBot: Saved the world] [20:10:26] [Server thread/INFO]: [TestBot: 16641 blocks filled] [20:10:27] [Server thread/INFO]: ThreadedAnvilChunkStorage (world): All chunks are saved [20:10:27] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM-1): All chunks are saved [20:10:27] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM1): All chunks are saved [20:10:27] [Server thread/INFO]: [TestBot: Saved the world] [20:10:28] [Server thread/INFO]: [TestBot: 16641 blocks filled] [20:10:30] [Server thread/INFO]: ThreadedAnvilChunkStorage (world): All chunks are saved [20:10:30] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM-1): All chunks are saved [20:10:30] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM1): All chunks are saved [20:10:30] [Server thread/INFO]: [TestBot: Saved the world] [20:10:31] [Server thread/INFO]: [TestBot: 16641 blocks filled] [20:10:31] [Server Watchdog/FATAL]: A single server tick took 60.00 seconds (should be max 0.05) [20:10:31] [Server Watchdog/FATAL]: Considering it to be crashed, server will forcibly shutdown. [20:10:32] [Server Watchdog/ERROR]: This crash report has been saved to: C:\pokechu22\testserver_1.11\.\crash-reports\crash-2016-09-08_20.10.32-server.txt [20:10:32] [Server Shutdown Thread/INFO]: Stopping server
Also, of note, occasionally /save-all flush results in multiple "All chunks are saved" messages. It's random and somewhat rare, but I think it happens more often when chunks are being loaded/unloaded than when standing still. These duplicate messages are a second indicator of this concurrency issue. When it happens, it looks like this:
[19:18:05] [Server thread/INFO]: [TestBot: Saved the world] [19:18:07] [File IO Thread/INFO]: ThreadedAnvilChunkStorage (world): All chunks are saved [19:18:07] [Server thread/INFO]: ThreadedAnvilChunkStorage (world): All chunks are saved [19:18:07] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM-1): All chunks are saved [19:18:07] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM1): All chunks are saved
This issue can also result in /save-all flush producing "An unknown error occurred while attempting to perform this command". While the stacktrace is not logged in that condition normally, a 1.10.2 server modified to print the stacktrace (only modification) resulted in this:
java.util.NoSuchElementException
at java.util.concurrent.ConcurrentHashMap$KeyIterator.next(ConcurrentHashMap.java:3416)
at atj.c(SourceFile:127)
at atj.b(SourceFile:163)
at lr.c(SourceFile:178)
at ls.q(SourceFile:903)
at ay.a(SourceFile:47)
at k.a(k.java:89)
at k.a(k.java:74)
at me.d(SourceFile:825)
at me.a(SourceFile:812)
at im.a(SourceFile:37)
at im.a(SourceFile:9)
at fl$1.run(SourceFile:13)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at h.a(SourceFile:45)
at net.minecraft.server.MinecraftServer.D(SourceFile:598)
at ld.D(SourceFile:338)
at net.minecraft.server.MinecraftServer.C(SourceFile:554)
at net.minecraft.server.MinecraftServer.run(SourceFile:458)
at java.lang.Thread.run(Thread.java:745)
My bot basically just repeated these commands, with the /fill s being there to have more dirty chunks (which might increase the chance of it happening, but also might not):
/fill ~-64 ~-1 ~-64 ~64 ~-1 ~64 minecraft:stained_hardened_clay color=red /save-all flush /fill ~-64 ~-1 ~-64 ~64 ~-1 ~64 minecraft:stained_hardened_clay color=blue /save-all flush
I ([Mod] Pokechu22) have written a tool that can recover your world by removing the duplicated block entities:
- For safety, make a complete backup of your world (this tool modifies files in-place).
- Download this program (source code). Make sure your browser saves it as a .jar file, not a .zip file.
- Run it. A window should open.
- Select "add files", and then find your world, enter the region folder, and select the mca file with the duplicate block entity. If you don't know which file that is, just select them all.
- Wait while the tool runs. Any duplicate block entities will be output in the log (full NBT); other chunks will just have counts.
- The world should now load ingame.
If you have any further information about this bug, please comment.
I thought that using structure blocks would allow me to copy-paste buildings, and it did. However, now that I've done it, opening the map crashes the game. There was another folder created (that wasn't there before) that had a weird symbol in front of the name, and I deleted that after it started crashing.
I honestly don't know if it can be reproduced, and I just want this world back. I hadn't backed it up in a while, and it was really important to me.
@[Mod] Pokechu22 - Thank you! I was watching this ticket as I have had a world I had spent months working on get corrupted (MCPE) and could not recover. I switched to the PC version as I could and do frequently back up worlds. I am now working a lot with structure blocks and this ticket you could say really was going to put damper on it. The knowledge these tools by Mojang devs (I don't like using mods) could help me recover a world is invaluable until the bug is identified and fixed.
The bug
When you start to connect to a server but it fails to connect for whatever reason, there is a chance that Minecraft might crash.
Code analysis
Based on 1.11 decompiled using MCP 9.35 rc1
The method net.minecraft.client.multiplayer.GuiConnecting.connect(String, int) creates a new thread to connect to a server. When the connection is closed a new net.minecraft.client.gui.GuiDisconnected is shown. The problem is that this class does not have a constructor and therefor the mc field storing the reference to the Minecraft instance remains null. This GUI is then displayed using the method net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) which would call the method net.minecraft.client.gui.GuiScreen.setWorldAndResolution(Minecraft, int, int) and set a value for the field. The problem here is that as this happens in a seperate thread the main thread might try to render this GUI already while the mc field is still null. This causes this crash then.
[Mod] Pokechu22 suggests in general to not directly call the Minecraft.displayGuiScreen(GuiScreen) method from other threads but instead create a Callable for it then call the method Minecraft.addScheduledTask(Callable<V> callableToSchedule) with it as argument.
How to reproduce (modded version)
Note: This can be reproduced with an unmodded version of Minecraft but there it will not always happen, whereas with this modification it should be always reproducible.
You can change the method net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) to sleep for some seconds before the method net.minecraft.client.gui.GuiScreen.setWorldAndResolution(Minecraft, int, int) of the GUI is called when this GUI is an instance of GuiDisconnected. Then Minecraft should crash if you try to connect to a server with a non-existant host or to an offline server.
To reproduce (jdb)
Similarly, adding a breakpoint in displayGuiScreen after assigning the field but before setWorldAndResolution can be used to trigger this same issue. As of 1.13-pre5, this is cep:712, so attaching jdb to a running minecraft and then entering stop at ceg:712 will let you reproduce this issue. Note that you will need to resume each time a new GUI has opened, so it may make sense to set the breakpoint only after entering the multiplayer screen. Once the breakpoint has been hit in a "Server Connector" thread, wait a few seconds and then enter resume one more time and the game will crash. (You may have to enter resume one more time).
Stacktrace
To make sure this report can be found when searching for the stacktrace
Description: Rendering screen java.lang.NullPointerException: Rendering screen at bho.d_(SourceFile:437) at bho.c(SourceFile:433) at bhc.a(SourceFile:44) at bqe.a(SourceFile:1078) at bes.av(SourceFile:993) at bes.a(SourceFile:398) at net.minecraft.client.main.Main.main(SourceFile:124)
The bug
The regex for integer arrays to distinct them from lists is
\[[-+\d|,\s]+\]
This matches int array items things like
+++ --- +-+- 1+1 1 \t\n\x0B\f\r4
which cannot be parsed as integers.
Note: It might be good if the string would be parsed as list if it could not be parsed as integer array, because a NBT list would be more obvious than a NBT string given that it matched the list requirements in the first place.
How to reproduce
- Use the following command
/give @p stone 1 0 {IntArrayTest:[+++,---,+-+-]} - Throw the item on the ground and inspect its NBT data
/entitydata @e[type=item,c=1] {}→ You will see that the tag IntArrayTest is a String (IntArrayTest:"[+++,---,+-+-]") instead of a list (IntArrayTest:["+++","---","+-+-"]), which means it matched the integer array pattern but could not be converted to an integer array
Suggested regex
The suggested regex could for example be
\[(?:[+-]?\d+\s*,\s*)*(?:[+-]?\d+)\]
by [Mod] Pokechu22
regexr link
or maybe with additional whitespaces in case somebody wants to parse a pretty printed integer array:
\[\s*(?:[+-]?\d+\s*,\s*)*[+-]?\d+\s*,?\]
Are the "network issues" mentioned here refer to server-side or client-side network issues? Like, if some server is too slow or fails to return a ping?
@Early Reflections at least the case described in the code analysis of the report is caused by client-side network issues, but it could be more visible if the server takes long to send packets back since the time span is longer then which makes it more likely that you have network issues during that.
@Timbawolf27 what do you mean by "I get the same message"? As [Mod] Pokechu22 said before "ticking screen" is only a crash report category. Additionally the error message and situation you are describing sounds pretty unrelated to this report. It is probably rather MC-115942.
The bug
Creating a new survival world after getting a new recipe in another world with the same name(Old: "New World", New: "New World", saved as "New World-") crashes the game while building terrain (it works fine when reloading it). Doesn't happen with the normal launcher (and resetting the settings with it fixes it for the new launcher too). Doesn't happen if the new world is not called the same or if you didn't get a new recipe before saving the world.
Crash report
---- Minecraft Crash Report ---- // You're mean. Time: 4/26/17 11:01 PM Description: Unexpected error java.lang.NullPointerException: Unexpected error at gf.a(SourceFile:234) at bhb.t(SourceFile:1687) at bhb.ax(SourceFile:964) at bhb.a(SourceFile:404) at net.minecraft.client.main.Main.main(SourceFile:123)
Hopper crash: MCX-3508750
Exit code: 65280
Crash analysis
gf.a(SourceFile:234) corresponds to NetworkManager.closeChannel(ITextComponent message).
public void closeChannel(ITextComponent message) { if (this.channel.isOpen()) { this.channel.close().awaitUninterruptibly(); // <-- this line this.terminationReason = message; } }
[Mod] Pokechu22: Given that it crashes on the second line and not in the if statement, channel is not null, but instead the ChannelFuture produced by calling close is.
I'm not entirely sure how that could happen, given that newPromise is called each time (within netty) and that shouldn't return null.
When you fly into a farmland block on elytra:
- farmland reverts to dirt,
- player model in 3rd person stands up,
- but camera and bounding box are stuck in flight mode.
If you slide out of the trampled block, flight mode ends, player stands up.
Code analysis / Fix
See this comment by [Mod] Pokechu22.
[Mod] Pokechu22 I already checked the code for pathfinding and even got them to walk through fire by returning PathNodeType.WALKABLE for EVERY mob when they see fire in the method net.minecraft.pathfinding.WalkNodeProcessor.getPathNodeTypeRaw(). I didn't realize that mobs could have different danger/pathfindig-priorities. Not 100% familiar with Minecraft's code, yet.
Thanks! Also, that debug path plugin channel is super cool! Didn't know something like that existed.
Yep! This bug can be fixed by setting the path priority for both DAMAGE_FIRE and DANGER_FIRE and maybe LAVA to 0.0F. Setting the path priority can be done by using the method setPathPriority. After that, Zombie Pigmen will also run through fire to kill you if you are mean to them.
public EntityPigZombie(World worldIn) { super(worldIn); this.setPathPriority(PathNodeType.DANGER_FIRE, 0.0F); this.setPathPriority(PathNodeType.DAMAGE_FIRE, 0.0F); this.isImmuneToFire = true; }
This bug is also not fixed because of the reversion of MC-93468.
Just do /gamerule randomTickSpeed 0 before you remove the source.
The fix of MC-93468 just made it more apparent that it is in the game, but it is not fixed by 1.12.2
(edit: Started writing this comment before [Mod] Pokechu22 reopend)
To answer [Mod] Pokechu22, it did work correctly in 1.12.2
The bug
Taking a screenshot fails when the folder of your game profile contains non-ASCII characters.
[22:40:50] [Client thread/WARN]: Couldn't save screenshot
java.io.IOException: Could not write image to the PNG file "###\screenshots\2018-02-11_22.40.50.png": Corrupt JPEG
at csp.a(SourceFile:306) ~[18w06a.jar:?]
at bxc.a(SourceFile:45) ~[18w06a.jar:?]
at bxc.a(SourceFile:30) ~[18w06a.jar:?]
at bwu.a(SourceFile:256) ~[18w06a.jar:?]
at org.lwjgl.glfw.GLFWKeyCallbackI.callback(GLFWKeyCallbackI.java:23) [lwjgl-glfw-3.1.2.jar:?]
at org.lwjgl.system.JNI.invokeV(Native Method) ~[lwjgl-3.1.2.jar:?]
at org.lwjgl.glfw.GLFW.glfwPollEvents(GLFW.java:2520) [lwjgl-glfw-3.1.2.jar:?]
at bwx.b(SourceFile:803) [18w06a.jar:?]
at bwx.a(SourceFile:383) [18w06a.jar:?]
at net.minecraft.client.main.Main.main(SourceFile:141) [18w06a.jar:?]
Additionally world icons cannot be saved either.
[22:45:42] [Client thread/WARN]: Couldn't save auto screenshot
java.io.IOException: Could not write image to the PNG file "###\saves\New World\icon.png": Corrupt JPEG
at csp.a(SourceFile:306) ~[18w06a.jar:?]
at cjr.n(SourceFile:1039) [18w06a.jar:?]
at cjr.a(SourceFile:949) [18w06a.jar:?]
at bwx.b(SourceFile:823) [18w06a.jar:?]
at bwx.a(SourceFile:383) [18w06a.jar:?]
at net.minecraft.client.main.Main.main(SourceFile:141) [18w06a.jar:?]
Besides the profile name also having non-ascii chars in the world name triggers that issue:
java.io.IOException: Could not write image to the PNG file "D:\mc\mn\bugs\.minecraft\saves\����BUG\icon.png": Corrupt JPEG
at deq.a(SourceFile:306) ~[18w20b.jar:?]
at cvd.o(SourceFile:870) [18w20b.jar:?]
at cvd.a(SourceFile:783) [18w20b.jar:?]
at cht.c(SourceFile:820) [18w20b.jar:?]
at cht.a(SourceFile:381) [18w20b.jar:?]
at net.minecraft.client.main.Main.main(SourceFile:144) [18w20b.jar:?]
How to reproduce
- Create a folder whose name contains non-ASCII characters, for example the following
äö²³§ß
- Launch Minecraft with this folder as game directory
- Try to take a screenshot
Code analysis
Code analysis by [Mod] Pokechu22 can be found in this comment.
The bug
As of the snapshots, any shapeless recipe cannot be crafted if any of its reagents are named or enchanted. This does not affect shaped recipes.
For example, "flint and steel" cannot be crafted if either ingredient has been renamed in an anvil. Regarding single-item recipes (such as bones to bonemeal or ingots to nuggets), the crafting files are inconsistent, sometimes defining them as shapeless and sometimes as shaped, but with one ingredient. Only recipes defined as shapeless are affected.
Code analysis by [Mod] Pokechu22:
In the snapshots, the code for ShapelessRecipes.matches was changed from using a List<Ingredient> and several loops checking ingredient.apply to using RecipeItemHelper and accountStack. ingredient.apply did not care about NBT, but in RecipeItemHelper:
public void accountStack(ItemStack stack) { if (!stack.isEmpty() && !stack.isItemDamaged() && !stack.isItemEnchanted() && !stack.hasDisplayName()) { int i = pack(stack); int j = stack.getCount(); this.increment(i, j); } }
Shaped recipes continue to use ingredient.apply, so they are not affected.
RecipeItemHelper is "mainly for the recipe book" deciding which items should be selected (to fix MC-116905), but it's also rendering those items invalid in the recipe itself. Again, this only affects shapeless recipes. If it is intended that named/enchanted items should be disallowed as crafting reagents, then shaped recipes should follow suit.
PLEase Do NOT mArk uNrelEASED VERSIOnS (anythIng StArTiNg WITh "fUture VeRsiOn") AS affeCTeD. yOU DoN'T hAvE AcCEss To thEM yET.
ALso, Just liKE [Mod] Pokechu22 sAid, ThiS is NOt A gLiTCH bUT yOU aRE SuPpoSED TO Die In the void. aFtEr alL, In REal life, You DiE As weLL IF You'rE iN tHE voiD.
Sorry for the late reply, [Mod] Pokechu22, I just reread your post. Yes, I mean the command is not working correctly, as it is not displaying NBT, and that is an issue for leather armor, as I updated the post.
@[Mod] Pokechu22 , I've tested your modified GLFW and it does indeed fix the issue with both RDP and KaVoom. Your efforts are stunningly impressive. I appreciate that this will take some time to filter it's way into the official release.
@[Mod] Pokechu22 this can also happen in singleplayer if your computer is not performing very well. It just happened to me.
The bug
Server does not launch using Java 10. It was working fine before 1.13-pre5 (1.13-pre4 included). I included the log of the crash. Both OpenJDK and Oracle's JRE are affected. This issue does not seem to occur when using Java 8.
[16:53:37] [Bootstrap 0/ERROR]: Unable to build datafixers java.util.ConcurrentModificationException: null at java.util.HashMap.computeIfAbsent(HashMap.java:1139) ~[?:?] at com.mojang.datafixers.DSL.taggedChoiceType(DSL.java:251) ~[server.jar:?] at com.mojang.datafixers.types.templates.TaggedChoice.lambda$null$1(TaggedChoice.java:72) ~[server.jar:?] at java.util.HashMap.computeIfAbsent(HashMap.java:1138) ~[?:?] at com.mojang.datafixers.types.templates.TaggedChoice.lambda$apply$2(TaggedChoice.java:71) ~[server.jar:?] at com.mojang.datafixers.types.templates.Named.lambda$apply$0(Named.java:43) ~[server.jar:?] at com.mojang.datafixers.types.templates.Check$1.apply(Check.java:45) ~[server.jar:?] at com.mojang.datafixers.types.templates.Sum$1.apply(Sum.java:50) ~[server.jar:?] at com.mojang.datafixers.types.templates.Sum$1.apply(Sum.java:50) ~[server.jar:?] at com.mojang.datafixers.types.templates.Sum$1.apply(Sum.java:50) ~[server.jar:?] at com.mojang.datafixers.types.templates.Sum$1.apply(Sum.java:50) ~[server.jar:?] at com.mojang.datafixers.types.families.RecursiveTypeFamily.lambda$null$1(RecursiveTypeFamily.java:107) ~[server.jar:?] at com.mojang.datafixers.types.templates.RecursivePoint$RecursivePointType.unfold(RecursivePoint.java:132) ~[server.jar:?] at com.mojang.datafixers.types.templates.RecursivePoint$RecursivePointType.findCheckedType(RecursivePoint.java:183) ~[server.jar:?] at com.mojang.datafixers.schemas.Schema.getType(Schema.java:80) ~[server.jar:?] at com.mojang.datafixers.DataFixerBuilder.lambda$build$1(DataFixerBuilder.java:68) ~[server.jar:?] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135) ~[?:?] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?] at java.lang.Thread.run(Thread.java:844) [?:?]
Code analysis
Code analysis by [Mod] Pokechu22 in this comment.
@[Mod] Pokechu22 I used a different directory. I have separate directories such as /Minecraft Saves - 2.0/, /Minecraft Saves - Latest Snapshot/, etc.
In the launcher's output log:
07:01:35 game Setting gameDir to: D:\Frank\Minecraft Saves\Minecraft Saves - 2.0
Leonov, Like [Mod] Pokechu22 said above:
This issue does not reproduce on my machine on windows, with several different kinds of mice. Can everyone experiencing this issue please give:
A) Their OS
B) The mouse they are using, and what kind of scroll wheel it has
Edit: Did you even adjust the mouseWheelSensitivity option in options.txt?
@[Mod] Pokechu22, but I think the whole point of this replacement is to prevent spam messages or messages of that kind, so I assume it should apply to nbsp characters as well. Otherwise I do not understand why this normalization is done in the first place.
[Mod] Pokechu22, the bug report includes two conditions and two outcomes. One condition is a vanilla state, whereas the other is using --workDir (which should be a workaround for the initial crash, but instead produces a different unexpected error).
Note in the last paragraph, the specific logs are matched to the tests. Your confusion results from mismatching tests and log results. If you'd like more or specific logs, I can happily produce them. Edit: To help clarify things, I've attached both Launcher_log files (with and without the --workDir argument).
My goal here is to focus on the underlying issue: common characters from certain languages prevent the game from running. This results in two distinct outcomes, depending on how the game is run. This bug report illustrates both.
Invalidating and moving my post is certainly fine, as long as we don't lose track of the broader issue and both errors that result (not just the single error listed in the target bug report).
[Mod] Pokechu22 I just attached the crash-report as you asked.
Also, I don't think anyone experienced the issue in 1.14.3, I definitely didn't and I have played a long time on that version.
The issue first appeared in 1.14 snapshots for me, in 19w06a according to this bug report and to my testing. Here is the list of version I tested and whether or not they are affected:
- 1.14.4 => yes
- 1.14.4-pre3 => yes
- 1.14.4-pre2 => yes
- 1.14.4-pre1 => no
- 1.14.3 => no
- 1.14.3-pre3 => no
- 1.14.3-pre2 => no
- 1.14.3-pre1 => yes
- 1.14.2 => yes
- 1.14.1 => yes
- 1.14 => yes
- 19w06a => yes
- 19w05a => no
- 19w02a => no
- 1.13.2 => no
So the problem was introduced in 19w06a, fixed in 1.14.3-pre2, and then re-introduced in 1.14.4-pre2.
I am running plasmashell 5.16.3 on Arch Linux and Minecraft is in a maximized window.
Turns out the root cause is the same, see @[Mod] Pokechu22's code analysis on the other ticket. Forward-resolving as duplicate.
I made another account because I wanted to change the username, so I don't need this account anymore
I read WEB-275
and a mod said the following
[Mod] Pokechu22 added a comment 22/Jul/18 8:23 PM edited
There is no way for you to delete your account; however, we can get an admin to do it for you. Create a new WEB issue saying "delete my account", and then we can assign it to the appropriate person.
(this is a newer policy that wasn't in place when this issue was originally created)
Permalink
[Mod] Pokechu22 added a comment - 06/Nov/19 11:53 PM
When you create the issue, you want to set the project to "Mojang Web Services (WEB)". The issue type remains as bug.
thx.
The bug
It looks like sometimes when closing the world the following error is logged (by the "Sound engine" thread):
Stop: Invalid name parameter.
(In 21w17a it was logged by class dns; com.mojang.blaze3d.audio.OpenAlUtil)
Exact reproduction steps are unknown, and it is not known either whether this has any noticable effect.
[Mod] Pokechu22 has found this occurrence of the error in a log file from 1.14.4, so the error does not appear to be new.





































The crash report
Didn't realize that went there, oops
Thanks, didn't know.
Sorry, I tried searching. Are there any tips for searching properly?
With mc-edit or the super flat preset shown. Super flat has many bugs, but here i'm pretty sure that it only means adding a few lines of error handling.
Semi-Visual actually, because the client thinks it is really there. If it happens on boats, you can stand on them. (But not get in them)
It stopped happening... And I didn't get a screenshot
I think it was a one-time glitch.
But these things shouldn't have been broken.
EDIT: Actually, another graphical glitch does occur. Watch the bottom piston.
It may not be accessible, but would bugs with locked chests or giants still be bugs? I think it can ocour in vanilla without any mods active, even if you need custom map downloads to access it, it is a bug. Giants can still be found in game in a way, their source code still exists, and if you have a map with a entityGiant, then it will exist.
No crash, just a one-frame graphical glitch. I wish I could use a slower computer, is there any way to make Minecraft really laggy? I don't think the crash would help. But if you replicate my design, you can see it flicker for one frame. It may be orientation specific, I will include the world.
World included.
They do exist in game, they just don't spawn. The code responsible for their spawning has the light level need to be less than 7 but also GREATER THAN 8. Therefore, they will never spawn, no mater where. The game may still try to spawn them, but the light is always wrong. You CAN use nbtedit to convert one mob to a giant, but you cant make a spawner.
From my cheaty source decompilation, I know that anr is the class that detects if Minecraft is modded. At least that's what it is in 13w06a. I have yet to figure out about zo, except that it extends zu.@James W
The crash occurs with Redstone on stairs/slabs/glowstone. The crash doesn't occur in some earlier versions. (13w03b, I think).
I have a scematic on the wiki: http://www.minecraftwiki.net/wiki/File:Giant_scematic.zip
This can be imported with mcedit if you want to derp about with giants. I think this should solve the problem of needing a giant.
Decompiled, ANR is redstone, and ZO is block update. Don't know how I got what I did before.
If they add a bud block it would be impossible to do things like 1:1 pixel displays. It already is impossible because of the trapdoor change. There was a design, but now there isn't. The best solution is a bud piston that behaves as it is now (then there could also be a bud block, but it would not break anything). It also breaks 4by4 and larger piston doors.
I would say that it MAY be a bug that Redstone blocks power pistons diagonally, that can be changed without any impact, it is a limit, but the whole quasiconectivity is very important. It is a bug, but so are chunk errors and creepers*, but those are iconic to Minecraft.
I actually wrote a essay on this, so I guess I will put a link to it.
http://www.minecraftforum.net/topic/1694360-why-the-bud-should-stay-essay/
*The creeper was originally a modeling error by notch while he was trying to make pigs.
Crash attached, but is it very usefull? Also, this glitch is rare, I had to launch Minecraft ~20 times for it to occur. I remember a Minecraft wiki post about a crash from a lwjgl error in 1.7.3, where Minecraft might crash if sound was turned off and on again because it failed to locate openAL, but that was fixed. Now if it fails, it doesn't try again.
... That was a cool video, but it isn't survival-feasible (or even non-mcedit creative). So even though it is cool, it still leaves some emptiness. And yes, creepers aren't bugs, But they were bugs, and then made into a feature. See what I'm saying?
That seems to have stopped it, because it didn't happen after 30 tries. I will have to see if it happens later though. While doing it, I learned that releasing alt in the launcher causes it to print out some gibberish if you ran it via the command line.
Done, was working on it as you posted.
And I mis-titled it. It is a chest crash.
Even though I STRONGLY feel that quasiconectivity is useful, with Redstone blocks it brakes tons of things. That is a bug. BUT, I am not asking for general quasiconectivity to be removed.
Oh, and Tavis Hansen, your design, while clever, is not infinity expandable, which was what made the design I showed so amazing.
Patching quasiconectivity with Redstone blocks would only break devices in snapshots that use that, and I don't see how you could use that. It would also fix the pistons getting stuck upwards.
Um... Don't put all the text in the title, and there is a description field.
Indeed, it is just an annoyance because sometimes I try to use the data in the crash report. I can use the scroll bar on the edge, but it is a really minor annoyance to have to, since the cursor defaults to the center.
The above text makes me sound lazy, though.
Not a bug. You are simply climbing the ladder, and the game thinks you are on the ladder, and thus gives ladder particles. The same may happen with vines, I haven't tested that.
A bud block can NOT replace the functionality of quasiconectivity, because it is used in other cases (EG piston doors). That's why it wont be fixed. Quasiconnectivity with Redstone blocks is annoying, and can be said a bug, because it breaks many logical things. Quasiconectivity with pressure plates... I need a picture, your design is non-intuitive (it sounds like you are trying to break the pressure plate). I wouldn't mind a bud piston, that might be a good compromise.
I have attached a world where there is a BIG line across the screen, it should appear. In case it doesn't, I also have a screenshot. (Please don't steal the device I included there, it is one I will make a video on sometime. It is really cool, and you can look at it if you want. )
EDIT: it still exist on all settings, it even exists in 3D mode (making for a weird occurrence)
I included that map because the lines occurred for me there.
@Tavis Hansen, I never said that Redstone blocks should be removed. Just that they don't power pistons like they do, fixing that problem. Also, the bud piston idea would probably be the best compromise, is there anything wrong with that?
I remember that in some early version, there was a semi-bug where the corners would not mesh. I think that is one of the 2 bugs on this page, the more annoying one is the random lines. The first one may be a issue with the way the boundaries of blocks are calculated. The second one may be a side effect of the opengl no texture icon, maybe? If there is a way to change that icon I might test that, but I have no idea how unfortunately.
Sorry to double post, but I now have evidence that the white stitching is actually transparent. With stone, it usually is you seeing the void. But you can see the transparency in this image. And I remember somewhere hearing about people using the transparency during beta to check for lava, I think. (I still think it is a bug, though. It should be patched. People who want x-ray should use glowstone or tnt)
The plugins are in the screenshot. The ip is hub.dwarfscraft.com, but the actual server was accessed by going through the portal labeled dvz2.
EDIT: oops wrong screenshot.
Ok, but if I do manage to reproduce in unmodded, I will reopen. (And isn't Minecraft 1 word and not capitalized like that?)
This still is the case occasionally, but it isn't that bad actually. They wont attack you, and you can't get them, so it is fine. Think floating squid and boat. They don't actually exist, they only do clientside. It isn't works as intended, but it is minor, so it could be "won't fix".
The behavior with dispensers and droppers allows for dispensers buds. Or more like dispenser rs nor latches without a reset. So it is annoying. The piston behavior can always be escaped, usually with a slab where it would receive power. Hopefully this helps.
I'm happy so long as the random giant lines are gone. The small dots aren't so bad.
Almost. I think that the resolution should be wont fix, since the exact way that the spawner tries to spawn is a bug. Oh, and I have included 2 schematics that actually can spawn giants. They work by spawning a mounted zombie, and it checks the light level. With the first, it will drop a zombie when the giant is killed, and with the second, the zombie has 0 health and despawns instantly. (Either when the giant dies or when it spawns, im not sure.) These spawners should be satisfactory, I hope.
Index out of bounds with pistons in states 6 or 7. I have some of them, and they crash on power.
The asdf seems to still occur when using the launcher from the command line. (java -Xmx1024M -Xms512M -cp minecraft.jar net.minecraft.LauncherFrame)
@ Dominik Banaszak It seems to still be annoying, can you give me a practical use of the part with redstone blocks? It latches the piston permanency. <rant>General quasiconectivity is nice, but these specific cases, the ones that Mojang wants to keep, seem very useless and inhibiting.
</rant>
This page should probably be divided into several reports: The behavior with droppers and dispensers, the behavior with Redstone blocks, and the behavior with pistons in general. The behavior that let dispensers fire multiple times (on rising and falling edges) was useful. Real-life circuitry is all about finding quirky behaviors and exploiting them. The transistor, a fundamental element of computing, essentially exploits a behavior that silicon exhibits. The effect of droppers and dispensers experiencing quasiconectivity is extremely annoying BECAUSE it is unavoidable. The same thing can be said for piston quasiconectivity with Redstone blocks. But with pistons in general, it is always avoidable using slabs, except in cases where the piston would still be powered if the behavior was removed.
For example, one can avoid powering a piston quasiconectivly by doing this (assume ██ is a full block, it was the best possible):
Before:
____________________
████████████████▒┫
________
██████▒┫
The upper line powers both pistons (or can hold the lower one on)
After:
____________________
██████▀▀████████▒┫
________
██████▒┫
The slab prevents the quasiconectivity. (I hope the full block characters show up right)
The reason for no bud block is that a bud block would be a pain, and it would probably need a tile entity if it were to be customizable. But if it had a tile entity, there would be no way to move it, so it would break bud trapdoors, and other things. Oh, and the explanation on why it works is great. Oh, and separating the redstone blocks and repeaters/levers may be good because it makes pistons jam and become unusable. For this, it could be that a redstone block doesn't power pistons facing upwards from 2 blocks above. (see image)
before:
██
¯¦̅
██
after
██
__
██
Man, we need a code to insert blocks.
Would this be a good compromise?
Fixed in 2.0! See Mojang.com
Ah, now I get it: while the placed block can use the openGL non-existent texture, the method for rendering is unable to handle this when it is flatly rendering it. Makes sense, but could also be fixed easily.
The asdf part is a bug for sure, but the stacktrace is common; try selecting multiplayer when you have networking off; it then puts a stacktrace out.
The hay bale issue is a duplicate of
MC-13599.Not a duplicate. Mine is about the fact that it says that you cannot place blocks, while you in fact can.
According to dictionary.com,
bug
1 [buhg] Show IPA noun, verb, bugged, bug·ging.
noun
1.
Also called true bug, hemipteran, hemipteron. a hemipterous insect.
2.
(loosely) any insect or insectlike invertebrate.
3.
Informal. any microorganism, especially a virus: He was laid up for a week by an intestinal bug.
4.
Informal. a defect or imperfection, as in a mechanical device, computer program, or plan; glitch: The test flight discovered the bugs in the new plane.
5.
Informal.
a.
a person who has a great enthusiasm for something; fan or hobbyist: a hi-fi bug.
b.
a craze or obsession: He's got the sports-car bug.
Bug means when something doesn't work as intended or breaks. This causes things to not work as intended, and also break things.
Even if it is a feature request for the new launcher, it was a feature of the old, and thus the fact that it is missing is a bug.
Ok, that makes sense. Besides, if I needed to get a new launcher anyways, then I would halve to do updating. Just curious, is version-changing functionality planed for the launcher? And will the old launcher always give you 1.5.1?
Nothing in the language files. I tried to manually add what I thought was the correct field, but that is auto-undone.
Probably the files just need updating.
How do you create them locally? I tried to create a folder and followed the naming convention, but I didn't do something right. Also, will there be any handler to avoid corruption, like a version tag?
Once again, this would probably be in the gray zone. The reason why I posted here rather then on the forums is because this was a behavior of the old launcher. Because it worked before, I would say that the absence of a past feature can be considered a bug (unless that feature was a bug :​p). Either way, it is something that should be in the final. I guess it would be better for me to put this in another report as well, but the new launcher doesn't respect lastlogin (remember password)
Tails, this isn't a duplicate of the other issue. What is happening is that you are stuck without a minecraft, maybe try changing the appdata directory so that it completely downloads.
On windows, you can do this with
Although you can chose whatever directory.
Also, when you launch, does it say done loading with a incomplete progress bar?
Ok, here is why it should not power with Redstone blocks:
It powers when the redstone block is next to it but not above it. (See images)
Also, the dispensers and droppers were not annoying because they could fire twice, but that BEHAVIOUR was removed, making dispensers "latch" and be all useless.
Piston quasiconectivity can always be "escaped" with a slab, so that is good.
No, but this is talking about an issue with a launcher, so if the launcher is modded, then it does mater.
Check your internet, and make sure you are spelling things right. It may be that it is down, as well.
Even more annoying with wolves; if you feed them, they enter love mode, but you are feeding to heal.
And with cats... You right click, they make the hearts, but they are love mode hearts. You wait a min for them to finish, then you try to tame again, with no success, then you ragequit.
Wait, the issue I am thinking of is how animals with hearts refuse to take food.
This is a random glitch thing, nonreproducable.
Ok, there are just a few things that are annoying, such as
I think the main reason why it annoys me is because the > normally represents a command, so it confuses me slightly. "Client: " would probably work well, and maybe in the console having multiple logs would also work.
Also, if the launcher can be closed after the game launches, what kinds of errors do you expect to occur in the launcher?
Also, when I want to start the client with more ram, you used to start the launcher with more, but now it looks like it is creating a separate process, so is there any way to specify how much ram you need?
I know this is a little bit of a feature request here, but maybe a way to tell the launcher not to append "Client> " before everything?
What was that with the new attachments of exe's? Were they viruses?
For a while it didn't show up in survival until you level up, was that patched too?
As I have said before, the main cause of annoyance with this behavior is when you get it when you don't expect it. Specifically, Redstone blocks and dispensers.
And a bud block doesn't make sense.
BUDs are odd, and couldn't be called intended. The way it works, if a bud block is added, it would be a unnecessary and sloppy solution. Integrating additional behaviors in pistons works well. Minecraft is a complex cellular automata, and is about using the behaviors of various blocks. Some are obvious, like pistons pushing, and others less, like repeater locking.
Ok, cant tell if it was fixed or not, but the cause has something to do with not drawing the bar when there is no level. It also doesn't show up until you get 1 level xp, not 1 xp point. Proof of this:
http://www.youtube.com/watch?feature=player_detailpage&v=ocBbgH2xQDw#t=1229s
It is not shown until etho gets xp and levels up.
I've been saying that it should be separated into several parts: Dropper/Dispenser quasiconectivity, General piston quasiconectivity, and redstone block quasiconectivity.
And for some reason, the idea of a BUD block makes me shudder (really), and I am not 100% sure why.
On a bukket server I was playing on, I have encountered chickens making suffocation noises and dying. Same problem, I think, except chickens have drops.
Create a small room, fill it with chickens, and you should see this.
Ok, I tried "adjksaldfjl" as a color, it did the same error. Interesting.
Get a computer with more ram, it is the out of memory error.
You may also with to look up how to start mc with more ram.
The issue here is that the game is running out of memory mid connection, and wont display the normal warning.
Would be easy to fix: add the right string to the language file.
Well, for the second one, it is a effect mobs can have, but they are potions, not mobs that give the effect.
So it may still be a bug.
(The second one is how /effect with invalid potion effects says mob effect)
The problem is that the message obstructs the command, not that there is a message.
My computer isn't the best, so that's why the message come up.
Now I cant teleport to NaN.
That isn't a fix.
Besides,
And I think this only describes nan and 0.
Better than wolves has a ton of things that don't "fit" minecraft.
Donuts, blood, poop, animal cruelty (slicing a wolf in half!?)...
So I think of it as a bad example.
--------------------------------------------------------------
I have decided that bud behavior is probably bad in dispensers and droppers, because very little can be done with it, and it ruins stuff.
True, it is a feature request, but by that logic, requesting a bug to be fixed is a feature request.
But the fact that it messes up the output like that is annoying.
That is a bug, I provided a solution. Yes, the solution is a feature request, but I think that this is still a bug report.
Try updating your lwjgl, and getting a real mouse (you may have already done both)
Try wood stairs, it may be effected by mc-something, the one where stone brick stairs are different.
I only tested the wood ones.
Also, it only happens on one side of the stairs, so try the left and right sides.
Looking at yours, I don't need to. See the second one?
It is messed up.
Might be hard to notice.
I'll make a quick texture pack to demonstrate.
Images attached.
The first one shows what it should look like, on other blocks.
The others show various stairs.
The crash seems to sometimes occur, sometimes not.
The pop is just NaN being awesome.
/kill doesn't work, but if you tp to a non-nan place, you should be fine.
I attached a screenshot, although I drew the device using symbols as well. I confirmed that it happened with both droppers and dispensers, and also occurs in all directions and across chunk boundaries (both on them and not on them).
The same thing also happens with pistons, but since they retract on lost power, while dispensers do nothing, that could be harnessed and it is not necessarily necessary to fix (I'm only talking about the behavior with pistons here, not the whole thing).
Oh, and you need to press the button twice, the first time it works fine and drops, but it only latches the second time.
I found it originally in this world, and narrowed it down to what I show here, but strangely the first issue I found may be different since I cannot replicate it in any other position. The device I screenshoted can be found at the back, and I tested it and got it to do this in many positions.
This world is probably irrelevant to the bug, but it may show another case where it happens. Press the button directly infront to see what happens. (You may need to press it several times)
Because I could, I confirmed that this also happens in 1.2.5, meaning that it is not a new glitch.
Go complain to apple.
Tell them to make better java or something.
A similar thing also happens on anvils, but they are anvils, so it doesn't matter much if two rows of pixels are flipped.
This is different. Probably the first bug that I was getting in my world is MC-11193, but this has to deal with the order in which redstone and buttons update is constant but is not in the right order.
In this case, the device constantly gets stuck, because the block is not updated twice on the same tick, after the redstone is updated.
Never mind, it is a similar bug, though dispenser quasiconectivity and piston quasiconnectivity are way different in importance.
The same thing happens with the black border around blocks and particles, though that is the least obvious part.
They are on the same delay. It doesn't always do it.
I supported power and no update, but power and an update works now since nothing gives updates anymore. You used to be able to do
[-█ ██▯
[
█ [][]To make both pistons extend ([]-[] is a fence gate and ▯ is a button).
Now, you can't.
I guess I support this, although it does break some things, they were already broken in 1.5.
And also, there are 3 other subsets: piston quasiconnectivity (Piston diagonal powering), droper/dispencer quasiconnectivity, which is droppers diagonal powering and latching, and piston quasiconnectivity with redstone blocks, which I sepperate because you can't turn off redstone blocks, so it basically freezes the piston.
Only regular piston quasiconnectivity can be argued for, since there are several workarounds for it. The others cause trouble.
@Manuel Since that issue is closed, your best option is to get optifine, which is not official, but may help you.
Yeah, I wish there were a happy middle. If only we could have 2 types of pistons, one that had it and one that didn't. But, as a mod said, that would be confusing.
The power but don't update approach worked well until you stopped being able to use fence gates to update pistons.
Now, I'm not sure.
The point this annoys people at the most is using redstone blocks, and the pistons "jamming".
Post it separately. It will help more.
How much snow did vechz place?
They are on the same delay, one flashes while the other doesn't.
It is confusing, and unreliable. Thus, it is a bug.
GAH.
The annoying part of this is how it works in some cases. You didn't read the potential uses.
I'm annoyed with redstone blocks too, but the other uses are worth keeping.
Well, in theory, you can do this in vanilla, using superflat presets.
Same with vines and stuff.
If you reenter the game, its fine, right?
If you need to restart multiple times, that works too.
And also, it is realy only a problem when the top piston "jams", there are other uses. And you can avoid it any way.
And how would you use that?
The only thing that could do is make a more expensive, slower variety to the redstone torch tower, that resets instantly and messes up pulses.
@Daniel
On windows, type windows key + r to open run, then type %appdata%
Open .minecraft
Open crash-reports
The most recent one should be on the bottom.
On other operating systems, run may not exist, but appdata still does.
Or you can just follow this link:
file:///%appdata%/.minecraft/crash-reports/
(For some reason, this may not work, just copy it into the browserbar then)
Well, I am pretty sure "%appdata%" is a global link that's used on all operating systems, not 100% sure though.
Thank you grum for intendifiying it.
@ Keybounce not quite sure what you mean.
But you probably can do this:
[-[]▁▁▁
[-[]██ :◀
[-[]▁▁▁██
[-[]██ :◀
[-[]▁▁▁██
[-[]██ :◀
All you do is power the back repeaters.
Show what you are trying to do, and I will show you how to do it.
Stop screaming.
Its just a set of numbers being changed.
Both of those imply some state; Won't fix implies that it is a bug, while works as intended implies it was intended in the first place. Thus, we need something like "Won't remove".
Wait, what? That's not true...
That's a crash, this isn't.
This is about fullscreening while a world is loading.
How is this works as intended? It adds several bugs, and makes no sense.
See
MC-23384.Also, the only reason why it was a duplicate of the other is it is assuming the other is a intended function, so it is a infinite loop.
I can assume this is a side-effect of the leash code.
Signs are fixed, but there are other side effects, see
MC-23384Renamed due to sign part fix in 1.6.2 and ocd not being major. Watch the video.
Its the root bug. The client interacts with the fence, and it thus ignores any of the place code. That's also the cause for the sign bug. I'll be using MCP to find the code that was changed.
Ok, here is the root bug, in MCP names:
/** * Called upon block activation (right click on the block.) */ public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { return par1World.isRemote ? true : ItemLeash.func_135066_a(par5EntityPlayer, par1World, par2, par3, par4); }It returns true if the world isn't remote, making the client always return true, and not place, but the server checks if there is a leash there.
The entire purpose of this change is so that when you rightclick on a fence with a lead, it does the rightclick animation. Is that really needed?
If set to false, all the buggy side-effects vanish, except leashes don't have the rightclick animation. That's fine, in my opinion.
Relates to or duplicates
MC-21433.Ignore the resolution on that bug, it is different.
Also, check my comment on it, I know the root cause and have made a fix.
No, he doesn't.
I shall post a video to explain.
It only effects me with the "snap" feature of windows 8.
See: http://youtu.be/zguYW76mwWI
That is true. However, I have no idea what caused it. Thus, it is non-reproducible. However, the file not found part may help.
I doubt this will happen for a while.
My one guess is that some weird code for skins caused it to try to load "textures/entity/steve.png", which probably was from a previous version.
The cause was likely a blip in my network, and the issue disappeared after reloging.
Still present.
It looks like a temporary blip, as the file exists and everything. If I find a way to reproduce, I will comment.
(I went through the source code, that path is used if no skin is found)
So, someone doesn't make a change to a behavior that was in the game for 2 years, and you get extremely mad?
Just work around it.
Or use his mod.
It is "fixed" in the weird way of them staying on for 1 cycle, then off the next, but it is somewhat stable. I will probably make a new ticket to describe this other effect, close this one.
Ok, first, the argument of this being non-obvious:
Hoppers locking when receiving redstone isn't obvious on first glance. I sometimes didn't account for that, and stuff didn't work. But, it was always the case, so in the future, I can account for it. Any change to preexisting behavior will break stuff. One change to a block isn't always this, as repeater locking didn't break anything (at least, it shouldn't have).
I had a veuge list of stuff that uses quasiconnectivity in some way on a early post, I'll fetch that.
Yes.
Yep.
Yes, but it should be resolved as "Wont fix".
See the earlier comments.
Yep.
Do note that realy large numbers don't work. 1000000000 does, but 4000000000 doesn't.
Ok, I have found that it is realy realy hard to track what will be broken.
I know for sure CNB's 4by4 door is broken, and a type of memory cell.
It is realy hard to test what will be broken.
Piston doors and buds are the primary use.
The thing is, while I like piston quasiconectivity, there is also dropper and dispencer quasiconnectivity.
That should be fixed, or debated at least.
No, they were kept so that not everything was destroyed on the change.
Seem similar?
Let me just say one thing.
You can spot the problem on first build with hoppers, and with quasiconnective pistons. (As in the problem exists when you build the machine). Changing quasiconectivity will simultaneously break many machines, including ones you forgot used this at all. You realize what a hastle it would be to go about and change every t flip-flop in my world? Even if the design isn't much bigger, it works slightly differently (power in different spots).
And most people (me included) probably wouldn't have expected that t flip-flop to be broken by the change anyway.
Ooh, this is the game being broken with 1.6.
Update your graphics card drivers.
Worst case, stick with 1.5.
No. The behavior has a ton of uses, including in piston doors and everything. Fiddle around with the mod mentioned earlier, you'll see what's broken. It's hard to figure out. Not only buds.
I have. There's many. It's hard to figure out which ones actualy are broken. So far, we have found 2 broken systems, one of which is the most common t-flipflop in the world, and will break 90% of all maps if broken. (That may be an exaduration, but it is a common design).
@Zé Carlos
Look, the point is, a design that common is broken. Many things are broken. There already are several quick fixes (putting redstone dust below the torches), but doing that requires large amounts of work.
Supose you are doing something extremely complicated. (http://forum.redstonedev.net/showthread.php?tid=1494 http://forum.redstonedev.net/showthread.php?tid=1651 ect.) How much fun would it be to go thru and replace every single t flip-flop? It would take ages, and the new design wouldn't be as compact.
And that was just a example.
You wouldn't realize how many things might be broken.
It wasn't fully explained. However, this video will help:
http://youtu.be/Z6XGZZnhUO0
(As I write this, it is uploading. Should be done soon)
@Zé Carlos
Then how does this effect you? Are you trying to remove this because it broke one of your machines?
Besides, there are ways to work around this before then. And even if we have new designs, the old t flip-flop is the most resource-light design. (Even with the change.) Thus, it is used a lot. And changing the thing that is used a lot?
And it would be a removal without a replacement. Unlike minecart boosters (with parallel minecarts).
I'm not saying that they cant be done. I'm saying that many prevalient designs have it used.
Oh, and you can often help "ignore" quasiconnectivity (in all cases exept those that have vertical redstone blocks) by using upsidedownslabs.
Like this curcit.
The upper and lower lines trigger seperatly.
████▂▂▂
▂▂▂██▀▀
███-]████
@Zé Carlos
Just get used to it.
There are a fair amount of things. Saying "I Don't understand this help plz!111!!!" (Which you didn't, this is intentionally exadurated) is not the correct response to a behavior that can be worked around, is stable, and has been in the game for 2 years.
My first reaction was confusion too. But it has been very helpful sinse I got over that.
Well, in my opinion, it has become too usefull to remove, even if it experiences bug-like side effects.
Whenever someone argues about keeping known bugs:
Creepers were origionaly a improperly moddled pig.
Bugs can lead to good things.
They said that this is no longer considered a bug.
I'm saying good things come from bugs sometimes.
This behavior (That's the most neutral term for it I can think of) is far to usefull to be removed.
Especially sinse it has been used for over two years, and can be established as a base property of pistons.
For one, you have a strongly negative attitude. However, the second paragraph is the optimal case.
I would, however, appreciate it still being craftable.
And, removing a thing that is the fundamental princable of many redstone contraptions, for example 3by3 and 4by4 doors, would be a terrible idea.
If you want proof that this is needed and removal will IRIPLACALBY break things, try building a 5by5 piston door without this.
And saying illogical/non-obvious things should be removed?
Well, repeater locking.
Who would have guessed that pointing a repeater into another would do that?
The only case where, with pistons, this breaks things, is a redstone block ontop of a piston.
Fixing that one thing, and breaking almost everything else?
NO.
And, you can generaly curcimvent this behavior with slabs.
And only in highly compact piston circuits does it become obvious.
And unless you jump right into advanced redstone without wiking anything, you should realize this happens.
And design circuits around it.
Not against it, hoping that it will be fixed magicly and then your circuit will work.
And, I have had my own circuits broken by this.
I don't complain, I use it in other circuits.
If it does require a total redesign, that annoys me a bit, but I prefer having the cases where it helps in the game.
Weird.
I cant reproduce at the moment, so I will need to continue testing.
For that behavior (
MC-1663), it should be kept.It's very usefull.
I'll need to look at my setup to figure out the problem.
@Brandon
No, i'm not.
There's many redstoners that use this.
And, others were arguing about this way before.
They just gave up on responding, this thing has spammed my inbox a ton.
Did you know that gmail resets threads every 100 messages?
Look through all the comments.
Or try.
This could/should be fixed by making a additional command (probably in /scoreboard) that compares the score of a player.
It would work like this:
Does this make sense?
Edited due to the text becoming linked improperly.
Negative response.
You realize this is about 2 years old now, from beta 1.7?
The main thing this breaks is transferring data upwards with a stack of pistons and redstone blocks.
And, that would just be a slower and less efficient way of sending signals up.
Please, lets just stop arguing, I don't want more inbox spam.
@Keybounce
The main argument about that idea is that it would confuse people to have two recipes.
In my opionion, that is just wrong, sinse the opisition of quasiconnectivity states that the current way is confusing, too.
I, personaly, think that maybe the recipie should use gold, although that doesn't make much sense from a design perspective.
It should use the same block id.
Or something like that, i'm fairly tired right now.
@tails
The main reason why that would break it anyway is because of a fix at some point that keeps you from being able to feed a animal twice.
The client thinks it is already fed, so when you step closer, it doesn't try again.
The server never says it happened.
mapmaking or experimental builds and would use the creative menu or the /give command to get the pistons anyway.
That isn't really a compromise, though. The typical survival player doesn't use redstone. And the budding pistons are used in most large doors and stuff, such as 3by3's, so a crafting recipe would be nice to keep so that I don't need to go and make 2000000 pistons so that I can have bud pistons. IE, those who would want it would want it, and you shouldn't make it annoying; that's basically removing bud pistons but not breaking builds, but it would break designs that already exist.
Even if the recipe is surrounding a piston with redstone in the crafting grid or using a repeater or torch instead.
Some recipes:
Yes, this is sugestiony, but I feel like we need to show the recipies, and I didn't feel like trying to use symbols.
@Lewis Moore
It was decided that it wont be fixed, although various solutionoids have been made.
Check my earlier post.
(Would you support two types of pistons?)
Do you think they may have glitched into a wall and suffocated?
Some time later.
Realy though, you should design hopper systems expecting this.
I see no way you could build something even when this doesn't happen, either hoppers would clog or you wouldn't experience this in the first place.
How is it far more eficent? You would have 2 chests for separate items, or a sorter that keeps non-smeltable items out.
The slot in the hopper would just get clogged, unless you mean that it auto-picks the slot.
As jl said in his stream, this will be a quick fix and reduce lag and make farms faster, with only 2 lines of code changed.
Please fix this.
Not the same bug. It relates, but it isn't a duplicate.
This is about how the number of mobs increases, but isn't divided evenly.
Suriously, these are different bugs; please don't say they are the same.
This is about players and the fact that one player gets more than another.
That is about how the server loading less chunks makes less mobs spawn.
They aren't the same.
What will it take for this not to be marked as duplicate?
Its a actual bug.
See also:
http://www.youtube.com/watch?v=q_DwPJZd2BU&lc=x5A39kZV71nNWwxVVU2kCunZQO0G408-kk9FQJeSE_IWANNA
@Ben Isbell
And because it is a real bug and the only way it would ever be fixed is if we say it needs to be fixed
_Look, that's a statement from what the current state is. Its like saying "Ok, so this buggy property exists" and writing that on the wiki makes in not a bug.
@Neospector
That doesn't mean it isn't a bug.
Well, actually, this was incited by a anylization of the source code,
http://www.youtube.com/watch?v=q_DwPJZd2BU&lc=x5A39kZV71nNWwxVVU2kCunZQO0G408-kk9FQJeSE_IWANNA
It is a bug; this doesn't make sense anyway.
And that's a if, which isn't the case. Test it; its uneven.
THE PROBLEM IS THAT THE CAP IS UNIVERSAL
Really. It gives one player more mobs than the others; if someone afk's at spawn with a dark area, they will have all the mobs if another player keeps killing their mobs at a perfect mob grinder.
The way it works generates buggy side effects. Are you saying that uneven mobs per player is intentional?
You need to change intended behaviours to fix bugs.
They aren't the same bug. That was how the world doesn't KEEP the data; this is how it doesnt save it and if the algorithem changes, everything breaks.
Wait, they are similar, except the description doesnt make them look similar due to talking about a way-older snapshot.
Well, people only post bug reports most of the time because the thing isn't working the way they want it or the way doesn't make sense. There are several other behavours that point out a problem and sugest a solution. So making less work for Mojang is bad?
Then why did they add hoppers? To collect the cobble you drop on the ground, not the drops from a 24-7 mob farm?
Well, if one player is afk, they hoard all the mobs, until there is none left. If other players keep reloging, you could reach a point where there are never any mobs. Basicly, this bug lets you make no mobs spawn due to a afk player.
Yea, hoppers do have other uses, this is just one of the more obvios and immediately useful ones.
True, but mobs spawning in caves and creepers don't burn. If you wait too long it can become inbalenced.
As for things that anoy you not being bugs, that's sometimes the case, and sometimes not. It was my best attempt at explaining.
This is a random occourence, but I am pretty sure it still happens. I havetn seen it, but I don't have any vilagers. Anyone getting it?
Well, that's a weird fix, but ok...
Did you fix the NPE when using a invalid color too?
My geuss is that they are related.
@Zachary
Yes, that is a bug, but Mojang decided they wont fix it due to various connected bugs.
Slog thru all the comments.
@Dirk Sohler
(That's from grum in the comments a while ago)
@Dirk Sohler
Look, this is a very usefull thing to have in the game.
The upwards piston behavior is annoying, but realy, its basicly a feature request there.
How many times are you going to use that?
This behavior is highly useful.
If I were to retype what I had said before 20 times, I would be able to answer every duplicate statement. IE, @Keybounce, don't you realize that I posted the design earlier?
I wish that we had both kinds, but if they don't implement this, its better to keep it like this.
Think of it like torch burnout: You don't find it useful but instead annoying, and you need to design your circuits around it, but there are some pretty amazing machines that work using it.
...No, wha? Nothing has changed...
Here's the other effect of this:
Suppose you have a giant sheep farm at spawn.
Spawn is always loaded.
Thus, you will have 5000 sheep always loaded.
Supose you wander around then.
The game will look at the number of animals, and see that there are 5000 there, past the mob cap, despite the fact that there are no animals for miles, thus no animals ever spawn.
It prints a stacktrace for "mob" and "monster", but doesn't show the message.
Likely because those are unrecognized keys, and "none" is also unrecognized. (or 0)
Easy fix for users: Bind the camera to f8.
Easy fix for Mojang: Bind the camera to f8.
Its not that hard; you can ignore the underlying problem (unrecognized keys == none), and just fix all instances.
Actualy, this is only on the x acsess, as far as I can tell,
Nope, its only with negative numbers.
Looks like a rounding issue here.
It displayed the error ""? What?
I think you have a typo.
Wait, so it is 2 off even?
Ok, that is some crazy rounding.
Havent gotten it yet, but this line from the output might be usefull:
(That's all it had)
Yes, but the errors are inconsistent, including the bottom one with the "critical command error".
What is "is blocked by" mean?
Isnt this basicly a duplicate?
@Paul Smith
The easiest way to work around this is with slabs. BTW, this has been in the game sinse pistons were added.
What are you trying to do with your contraption?
If the issue you are having is actually related to MC-11193 (this video:http://www.youtube.com/watch?v=e5hUYLC8Tms), then slabs MAY fix your problem, but so could a number of other things.
If need be, you can upload a picture of your contraption and I can try to fix it.
This causes https://mojang.atlassian.net/browse/MCL-1517, or appears to do so.
Please return them, or something.
Duplicate of
MC-31669.Or that is a duplicate of this. The other one has a lower value, though.
Not quite. That only applies to the enchant glow, this is all items.
They are strongly related, but different.
Doesn't ocour on c; I just discovered this after uploading.
Please mark as fixed.
Utoh, does that mean that my 34 (piston head) in item frames for decoration will destroy the world?
Great...
I tested the file path by running it, and it works fine. And, as far as I can tell, nothing is criticaly wrong with my hard drive.
It happens even in default locations (when I did not modify the location of appdata or the game save location).
Here's some system details from a unrelated crash:
Hm.. Screenshots open in paint, would that do anything? (Paint does "hold" command-line input...)
I changed to photo gallery, and now it works. Still a bug that it doesn't work when set to paint, but that fixes it.
Mipmap levels at 4 makes this realy bad.
Setting it to 0 makes it disappear for me.
I have anthroscopic filtering off.
That's true.
Another interesting thing:
/summon Creeper ~ {Tag:Value}also doesn't work.
I agree.
But, interestingly, you actualy still gain the effect of blocking while looking at a fence, and you can move at full speed too.
So it is abusable.
The easiest fix is to change the oneline of code when it is activated (right clicked) from
/** * Called upon block activation (right click on the block.) */ public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { return par1World.isRemote ? true : ItemLeash.func_135066_a(par5EntityPlayer, par1World, par2, par3, par4); }to
/** * Called upon block activation (right click on the block.) */ public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { return par1World.isRemote ? false : ItemLeash.func_135066_a(par5EntityPlayer, par1World, par2, par3, par4); }(Basicly what that does is: If the game is in multiplayer, always do the rightclick action for the fence clientside (and skip placement), while on the server, it does a fence action only if there is a lead, otherwise it places the block.)
Changing that will make it default to not placing clientside, with the negative effect of no right click effect when rightclicking on a leash, and the positive effect of fixing a x-ray bug, fast movement while blocking, and several other things.
(And you probably could make it have no negative effects with a bit of work)
I searched for "command-line output".
And, actualy, this is about the output command-line, the other one is about the logs. They are strongly related, however.
This applies to both gamerules effecting drops.
It's getting really annoying because boats are piling up to a extreme level with a device of mine, and there is no way of safely removing said boats.
Well, it is weird still.
1, I would like to see some stats on that. It is rather annoying.
2, It is confusing until you learn how to do it, but so is A) Java, B) Most of (or all of) all other redstone, C) The human body, D) Command blocks, and E) Nbt stuff.
3, It is rather easy to work around it, once you understand WHAT is happening, it is easy to figure out how to avoid it.
Generally, play around with using upsidedown slabs (/give @p 44 1 8) to insulate from this behavior. It wont be changed, so figure out how to avoid it until you start using it.
Sometime, they may add a non-quasi piston, but this will not be removed.
By it counting as a redstone block when extended, do you mean that it can receive redstone?
Can you post a picture or diagram of your current design?
Ah, that problem. Yea, that's the one major problem with this behavior: it can make that almost impossible.
You can pulse the row and then give a 2-tick pulse to the row below, but that still is a pain.
It can be done, however.
This is a old (now broken) design that depended on this and a additional block-updating behavior, there is a version for 1.5+ but I'm not sure where.
http://www.youtube.com/watch?v=sN6EmfmgJic&list=TLlmJrzHq6S3ahyn8m0I-OhyXDs4LvZ3xT
Try this:
 ▂▂ 
▀▀┯
████
I cant tell exactly what you are doing, but if you want to try redrawing your symbols, heres the text I used for mine:
{color:brown} ▂▂ {color} ▀▀┯ {color:white}██{color}██Not fixed exactly, as of b.
Edit: Interestingly, I did the command 3 times and got a error message twice, then a crash.
And now this one, which actualy opened in the launcher unlike the other...
I did /give pokechu22 999999 3 times and then it crashed on the fourth.
And, it just deleted my world... Yay for bug testing...
In short, the entire problem is because the bugtracker can't let you lock it, and Mojang only includes a few resolutions.