114 lines
3.4 KiB
Java
114 lines
3.4 KiB
Java
package net.minecraft.client.sounds;
|
|
|
|
import com.google.common.collect.Sets;
|
|
import com.mojang.blaze3d.audio.Channel;
|
|
import com.mojang.blaze3d.audio.Library;
|
|
import java.util.Iterator;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.function.Consumer;
|
|
import java.util.stream.Stream;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
* The ChannelAccess class provides access to channels for playing audio data using a given library and executor.
|
|
*/
|
|
@Environment(EnvType.CLIENT)
|
|
public class ChannelAccess {
|
|
private final Set<ChannelAccess.ChannelHandle> channels = Sets.newIdentityHashSet();
|
|
final Library library;
|
|
final Executor executor;
|
|
|
|
public ChannelAccess(Library library, Executor executor) {
|
|
this.library = library;
|
|
this.executor = executor;
|
|
}
|
|
|
|
/**
|
|
* Creates a new channel handle for the specified system mode and returns a CompletableFuture that completes with the handle when it is created.
|
|
* <p>
|
|
* @return a CompletableFuture that completes with the channel handle when it is created, or null if it cannot be created
|
|
*
|
|
* @param systemMode systemMode the system mode to create the channel handle for
|
|
*/
|
|
public CompletableFuture<ChannelAccess.ChannelHandle> createHandle(Library.Pool systemMode) {
|
|
CompletableFuture<ChannelAccess.ChannelHandle> completableFuture = new CompletableFuture();
|
|
this.executor.execute(() -> {
|
|
Channel channel = this.library.acquireChannel(systemMode);
|
|
if (channel != null) {
|
|
ChannelAccess.ChannelHandle channelHandle = new ChannelAccess.ChannelHandle(channel);
|
|
this.channels.add(channelHandle);
|
|
completableFuture.complete(channelHandle);
|
|
} else {
|
|
completableFuture.complete(null);
|
|
}
|
|
});
|
|
return completableFuture;
|
|
}
|
|
|
|
/**
|
|
* @param sourceStreamConsumer the consumer to execute on the stream of channels
|
|
*/
|
|
public void executeOnChannels(Consumer<Stream<Channel>> sourceStreamConsumer) {
|
|
this.executor.execute(() -> sourceStreamConsumer.accept(this.channels.stream().map(channelHandle -> channelHandle.channel).filter(Objects::nonNull)));
|
|
}
|
|
|
|
public void scheduleTick() {
|
|
this.executor.execute(() -> {
|
|
Iterator<ChannelAccess.ChannelHandle> iterator = this.channels.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
ChannelAccess.ChannelHandle channelHandle = (ChannelAccess.ChannelHandle)iterator.next();
|
|
channelHandle.channel.updateStream();
|
|
if (channelHandle.channel.stopped()) {
|
|
channelHandle.release();
|
|
iterator.remove();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public void clear() {
|
|
this.channels.forEach(ChannelAccess.ChannelHandle::release);
|
|
this.channels.clear();
|
|
}
|
|
|
|
/**
|
|
* Represents a handle to a channel.
|
|
*/
|
|
@Environment(EnvType.CLIENT)
|
|
public class ChannelHandle {
|
|
@Nullable
|
|
Channel channel;
|
|
private boolean stopped;
|
|
|
|
/**
|
|
* {@return {@code true} if the channel has been stopped, {@code false} otherwise}
|
|
*/
|
|
public boolean isStopped() {
|
|
return this.stopped;
|
|
}
|
|
|
|
public ChannelHandle(final Channel channel) {
|
|
this.channel = channel;
|
|
}
|
|
|
|
public void execute(Consumer<Channel> soundConsumer) {
|
|
ChannelAccess.this.executor.execute(() -> {
|
|
if (this.channel != null) {
|
|
soundConsumer.accept(this.channel);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void release() {
|
|
this.stopped = true;
|
|
ChannelAccess.this.library.releaseChannel(this.channel);
|
|
this.channel = null;
|
|
}
|
|
}
|
|
}
|