minecraft-src/net/minecraft/client/sounds/SoundBufferLibrary.java
2025-07-04 01:41:11 +03:00

120 lines
4.1 KiB
Java

package net.minecraft.client.sounds;
import com.google.common.collect.Maps;
import com.mojang.blaze3d.audio.SoundBuffer;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.Util;
import net.minecraft.client.resources.sounds.Sound;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceProvider;
/**
* The {@linkplain SoundBufferLibrary} class provides a cache containing instances of {@linkplain SoundBuffer} and {@linkplain AudioStream} for use in Minecraft sound handling.
*/
@Environment(EnvType.CLIENT)
public class SoundBufferLibrary {
/**
* The {@linkplain ResourceProvider} used for loading sound resources.
*/
private final ResourceProvider resourceManager;
private final Map<ResourceLocation, CompletableFuture<SoundBuffer>> cache = Maps.<ResourceLocation, CompletableFuture<SoundBuffer>>newHashMap();
public SoundBufferLibrary(ResourceProvider resourceManager) {
this.resourceManager = resourceManager;
}
/**
* {@return Returns a {@linkplain CompletableFuture} containing the complete {@linkplain SoundBuffer}. The {@linkplain SoundBuffer} is loaded asynchronously and cached.}
*
* @param soundID the {@linkplain ResourceLocation} of the sound
*/
public CompletableFuture<SoundBuffer> getCompleteBuffer(ResourceLocation soundID) {
return (CompletableFuture<SoundBuffer>)this.cache.computeIfAbsent(soundID, resourceLocation -> CompletableFuture.supplyAsync(() -> {
try {
InputStream inputStream = this.resourceManager.open(resourceLocation);
SoundBuffer var5;
try {
FiniteAudioStream finiteAudioStream = new JOrbisAudioStream(inputStream);
try {
ByteBuffer byteBuffer = finiteAudioStream.readAll();
var5 = new SoundBuffer(byteBuffer, finiteAudioStream.getFormat());
} catch (Throwable var8) {
try {
finiteAudioStream.close();
} catch (Throwable var7) {
var8.addSuppressed(var7);
}
throw var8;
}
finiteAudioStream.close();
} catch (Throwable var9) {
if (inputStream != null) {
try {
inputStream.close();
} catch (Throwable var6) {
var9.addSuppressed(var6);
}
}
throw var9;
}
if (inputStream != null) {
inputStream.close();
}
return var5;
} catch (IOException var10) {
throw new CompletionException(var10);
}
}, Util.nonCriticalIoPool()));
}
/**
* {@return Returns a {@linkplain CompletableFuture} containing the {@linkplain AudioStream}. The {@linkplain AudioStream} is loaded asynchronously.}
*
* @param resourceLocation the {@linkplain ResourceLocation} of the sound
* @param isWrapper whether the {@linkplain AudioStream} should be a {@linkplain LoopingAudioStream}
*/
public CompletableFuture<AudioStream> getStream(ResourceLocation resourceLocation, boolean isWrapper) {
return CompletableFuture.supplyAsync(() -> {
try {
InputStream inputStream = this.resourceManager.open(resourceLocation);
return (AudioStream)(isWrapper ? new LoopingAudioStream(JOrbisAudioStream::new, inputStream) : new JOrbisAudioStream(inputStream));
} catch (IOException var4) {
throw new CompletionException(var4);
}
}, Util.nonCriticalIoPool());
}
/**
* Clears the cache of all {@linkplain SoundBuffer} instances.
*/
public void clear() {
this.cache.values().forEach(completableFuture -> completableFuture.thenAccept(SoundBuffer::discardAlBuffer));
this.cache.clear();
}
/**
* Preloads the {@linkplain SoundBuffer} objects for the specified collection of sounds.
* <p>
* @return a {@linkplain CompletableFuture} representing the completion of the preload operation
*
* @param sounds the collection of sounds to preload
*/
public CompletableFuture<?> preload(Collection<Sound> sounds) {
return CompletableFuture.allOf((CompletableFuture[])sounds.stream().map(sound -> this.getCompleteBuffer(sound.getPath())).toArray(CompletableFuture[]::new));
}
}