509 lines
23 KiB
Java
509 lines
23 KiB
Java
|
package net.minecraft.client.sounds;
|
||
|
|
||
|
import com.google.common.collect.HashMultimap;
|
||
|
import com.google.common.collect.Lists;
|
||
|
import com.google.common.collect.Maps;
|
||
|
import com.google.common.collect.Multimap;
|
||
|
import com.google.common.collect.Sets;
|
||
|
import com.mojang.blaze3d.audio.Channel;
|
||
|
import com.mojang.blaze3d.audio.Library;
|
||
|
import com.mojang.blaze3d.audio.Listener;
|
||
|
import com.mojang.blaze3d.audio.ListenerTransform;
|
||
|
import com.mojang.blaze3d.audio.SoundBuffer;
|
||
|
import com.mojang.logging.LogUtils;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.List;
|
||
|
import java.util.Map;
|
||
|
import java.util.Set;
|
||
|
import java.util.Map.Entry;
|
||
|
import java.util.concurrent.CompletableFuture;
|
||
|
import java.util.concurrent.atomic.AtomicReference;
|
||
|
import java.util.stream.Stream;
|
||
|
import javax.annotation.Nullable;
|
||
|
import net.minecraft.SharedConstants;
|
||
|
import net.minecraft.Util;
|
||
|
import net.minecraft.client.Camera;
|
||
|
import net.minecraft.client.Options;
|
||
|
import net.minecraft.client.resources.sounds.Sound;
|
||
|
import net.minecraft.client.resources.sounds.SoundInstance;
|
||
|
import net.minecraft.client.resources.sounds.TickableSoundInstance;
|
||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||
|
import net.minecraft.resources.ResourceLocation;
|
||
|
import net.minecraft.server.packs.resources.ResourceProvider;
|
||
|
import net.minecraft.sounds.SoundEvent;
|
||
|
import net.minecraft.sounds.SoundEvents;
|
||
|
import net.minecraft.sounds.SoundSource;
|
||
|
import net.minecraft.util.Mth;
|
||
|
import net.minecraft.world.phys.Vec3;
|
||
|
import net.minecraftforge.api.distmarker.Dist;
|
||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||
|
import org.slf4j.Logger;
|
||
|
import org.slf4j.Marker;
|
||
|
import org.slf4j.MarkerFactory;
|
||
|
|
||
|
@OnlyIn(Dist.CLIENT)
|
||
|
public class SoundEngine {
|
||
|
private static final Marker MARKER = MarkerFactory.getMarker("SOUNDS");
|
||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||
|
private static final float PITCH_MIN = 0.5F;
|
||
|
private static final float PITCH_MAX = 2.0F;
|
||
|
private static final float VOLUME_MIN = 0.0F;
|
||
|
private static final float VOLUME_MAX = 1.0F;
|
||
|
private static final int MIN_SOURCE_LIFETIME = 20;
|
||
|
private static final Set<ResourceLocation> ONLY_WARN_ONCE = Sets.newHashSet();
|
||
|
private static final long DEFAULT_DEVICE_CHECK_INTERVAL_MS = 1000L;
|
||
|
public static final String MISSING_SOUND = "FOR THE DEBUG!";
|
||
|
public static final String OPEN_AL_SOFT_PREFIX = "OpenAL Soft on ";
|
||
|
public static final int OPEN_AL_SOFT_PREFIX_LENGTH = "OpenAL Soft on ".length();
|
||
|
private final SoundManager soundManager;
|
||
|
private final Options options;
|
||
|
private boolean loaded;
|
||
|
private final Library library = new Library();
|
||
|
private final Listener listener = this.library.getListener();
|
||
|
private final SoundBufferLibrary soundBuffers;
|
||
|
private final SoundEngineExecutor executor = new SoundEngineExecutor();
|
||
|
private final ChannelAccess channelAccess = new ChannelAccess(this.library, this.executor);
|
||
|
private int tickCount;
|
||
|
private long lastDeviceCheckTime;
|
||
|
private final AtomicReference<SoundEngine.DeviceCheckState> devicePoolState = new AtomicReference<>(SoundEngine.DeviceCheckState.NO_CHANGE);
|
||
|
private final Map<SoundInstance, ChannelAccess.ChannelHandle> instanceToChannel = Maps.newHashMap();
|
||
|
private final Multimap<SoundSource, SoundInstance> instanceBySource = HashMultimap.create();
|
||
|
private final List<TickableSoundInstance> tickingSounds = Lists.newArrayList();
|
||
|
private final Map<SoundInstance, Integer> queuedSounds = Maps.newHashMap();
|
||
|
private final Map<SoundInstance, Integer> soundDeleteTime = Maps.newHashMap();
|
||
|
private final List<SoundEventListener> listeners = Lists.newArrayList();
|
||
|
private final List<TickableSoundInstance> queuedTickableSounds = Lists.newArrayList();
|
||
|
private final List<Sound> preloadQueue = Lists.newArrayList();
|
||
|
|
||
|
public SoundEngine(SoundManager p_120236_, Options p_120237_, ResourceProvider p_249332_) {
|
||
|
this.soundManager = p_120236_;
|
||
|
this.options = p_120237_;
|
||
|
this.soundBuffers = new SoundBufferLibrary(p_249332_);
|
||
|
}
|
||
|
|
||
|
public void reload() {
|
||
|
ONLY_WARN_ONCE.clear();
|
||
|
|
||
|
for (SoundEvent soundevent : BuiltInRegistries.SOUND_EVENT) {
|
||
|
if (soundevent != SoundEvents.EMPTY) {
|
||
|
ResourceLocation resourcelocation = soundevent.location();
|
||
|
if (this.soundManager.getSoundEvent(resourcelocation) == null) {
|
||
|
LOGGER.warn("Missing sound for event: {}", BuiltInRegistries.SOUND_EVENT.getKey(soundevent));
|
||
|
ONLY_WARN_ONCE.add(resourcelocation);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.destroy();
|
||
|
this.loadLibrary();
|
||
|
}
|
||
|
|
||
|
private synchronized void loadLibrary() {
|
||
|
if (!this.loaded) {
|
||
|
try {
|
||
|
String s = this.options.soundDevice().get();
|
||
|
this.library.init("".equals(s) ? null : s, this.options.directionalAudio().get());
|
||
|
this.listener.reset();
|
||
|
this.listener.setGain(this.options.getSoundSourceVolume(SoundSource.MASTER));
|
||
|
this.soundBuffers.preload(this.preloadQueue).thenRun(this.preloadQueue::clear);
|
||
|
this.loaded = true;
|
||
|
LOGGER.info(MARKER, "Sound engine started");
|
||
|
} catch (RuntimeException runtimeexception) {
|
||
|
LOGGER.error(MARKER, "Error starting SoundSystem. Turning off sounds & music", (Throwable)runtimeexception);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private float getVolume(@Nullable SoundSource p_120259_) {
|
||
|
return p_120259_ != null && p_120259_ != SoundSource.MASTER ? this.options.getSoundSourceVolume(p_120259_) : 1.0F;
|
||
|
}
|
||
|
|
||
|
public void updateCategoryVolume(SoundSource p_120261_, float p_120262_) {
|
||
|
if (this.loaded) {
|
||
|
if (p_120261_ == SoundSource.MASTER) {
|
||
|
this.listener.setGain(p_120262_);
|
||
|
} else {
|
||
|
this.instanceToChannel.forEach((p_120280_, p_120281_) -> {
|
||
|
float f = this.calculateVolume(p_120280_);
|
||
|
p_120281_.execute(p_174990_ -> {
|
||
|
if (f <= 0.0F) {
|
||
|
p_174990_.stop();
|
||
|
} else {
|
||
|
p_174990_.setVolume(f);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void destroy() {
|
||
|
if (this.loaded) {
|
||
|
this.stopAll();
|
||
|
this.soundBuffers.clear();
|
||
|
this.library.cleanup();
|
||
|
this.loaded = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void emergencyShutdown() {
|
||
|
if (this.loaded) {
|
||
|
this.library.cleanup();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void stop(SoundInstance p_120275_) {
|
||
|
if (this.loaded) {
|
||
|
ChannelAccess.ChannelHandle channelaccess$channelhandle = this.instanceToChannel.get(p_120275_);
|
||
|
if (channelaccess$channelhandle != null) {
|
||
|
channelaccess$channelhandle.execute(Channel::stop);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void setVolume(SoundInstance p_377242_, float p_376894_) {
|
||
|
if (this.loaded) {
|
||
|
ChannelAccess.ChannelHandle channelaccess$channelhandle = this.instanceToChannel.get(p_377242_);
|
||
|
if (channelaccess$channelhandle != null) {
|
||
|
channelaccess$channelhandle.execute(p_374745_ -> p_374745_.setVolume(p_376894_ * this.calculateVolume(p_377242_)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void stopAll() {
|
||
|
if (this.loaded) {
|
||
|
this.executor.flush();
|
||
|
this.instanceToChannel.values().forEach(p_120288_ -> p_120288_.execute(Channel::stop));
|
||
|
this.instanceToChannel.clear();
|
||
|
this.channelAccess.clear();
|
||
|
this.queuedSounds.clear();
|
||
|
this.tickingSounds.clear();
|
||
|
this.instanceBySource.clear();
|
||
|
this.soundDeleteTime.clear();
|
||
|
this.queuedTickableSounds.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void addEventListener(SoundEventListener p_120296_) {
|
||
|
this.listeners.add(p_120296_);
|
||
|
}
|
||
|
|
||
|
public void removeEventListener(SoundEventListener p_120308_) {
|
||
|
this.listeners.remove(p_120308_);
|
||
|
}
|
||
|
|
||
|
private boolean shouldChangeDevice() {
|
||
|
if (this.library.isCurrentDeviceDisconnected()) {
|
||
|
LOGGER.info("Audio device was lost!");
|
||
|
return true;
|
||
|
} else {
|
||
|
long i = Util.getMillis();
|
||
|
boolean flag = i - this.lastDeviceCheckTime >= 1000L;
|
||
|
if (flag) {
|
||
|
this.lastDeviceCheckTime = i;
|
||
|
if (this.devicePoolState.compareAndSet(SoundEngine.DeviceCheckState.NO_CHANGE, SoundEngine.DeviceCheckState.ONGOING)) {
|
||
|
String s = this.options.soundDevice().get();
|
||
|
Util.ioPool().execute(() -> {
|
||
|
if ("".equals(s)) {
|
||
|
if (this.library.hasDefaultDeviceChanged()) {
|
||
|
LOGGER.info("System default audio device has changed!");
|
||
|
this.devicePoolState.compareAndSet(SoundEngine.DeviceCheckState.ONGOING, SoundEngine.DeviceCheckState.CHANGE_DETECTED);
|
||
|
}
|
||
|
} else if (!this.library.getCurrentDeviceName().equals(s) && this.library.getAvailableSoundDevices().contains(s)) {
|
||
|
LOGGER.info("Preferred audio device has become available!");
|
||
|
this.devicePoolState.compareAndSet(SoundEngine.DeviceCheckState.ONGOING, SoundEngine.DeviceCheckState.CHANGE_DETECTED);
|
||
|
}
|
||
|
|
||
|
this.devicePoolState.compareAndSet(SoundEngine.DeviceCheckState.ONGOING, SoundEngine.DeviceCheckState.NO_CHANGE);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return this.devicePoolState.compareAndSet(SoundEngine.DeviceCheckState.CHANGE_DETECTED, SoundEngine.DeviceCheckState.NO_CHANGE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void tick(boolean p_120303_) {
|
||
|
if (this.shouldChangeDevice()) {
|
||
|
this.reload();
|
||
|
}
|
||
|
|
||
|
if (!p_120303_) {
|
||
|
this.tickNonPaused();
|
||
|
}
|
||
|
|
||
|
this.channelAccess.scheduleTick();
|
||
|
}
|
||
|
|
||
|
private void tickNonPaused() {
|
||
|
this.tickCount++;
|
||
|
this.queuedTickableSounds.stream().filter(SoundInstance::canPlaySound).forEach(this::play);
|
||
|
this.queuedTickableSounds.clear();
|
||
|
|
||
|
for (TickableSoundInstance tickablesoundinstance : this.tickingSounds) {
|
||
|
if (!tickablesoundinstance.canPlaySound()) {
|
||
|
this.stop(tickablesoundinstance);
|
||
|
}
|
||
|
|
||
|
tickablesoundinstance.tick();
|
||
|
if (tickablesoundinstance.isStopped()) {
|
||
|
this.stop(tickablesoundinstance);
|
||
|
} else {
|
||
|
float f = this.calculateVolume(tickablesoundinstance);
|
||
|
float f1 = this.calculatePitch(tickablesoundinstance);
|
||
|
Vec3 vec3 = new Vec3(tickablesoundinstance.getX(), tickablesoundinstance.getY(), tickablesoundinstance.getZ());
|
||
|
ChannelAccess.ChannelHandle channelaccess$channelhandle = this.instanceToChannel.get(tickablesoundinstance);
|
||
|
if (channelaccess$channelhandle != null) {
|
||
|
channelaccess$channelhandle.execute(p_194478_ -> {
|
||
|
p_194478_.setVolume(f);
|
||
|
p_194478_.setPitch(f1);
|
||
|
p_194478_.setSelfPosition(vec3);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Iterator<Entry<SoundInstance, ChannelAccess.ChannelHandle>> iterator = this.instanceToChannel.entrySet().iterator();
|
||
|
|
||
|
while (iterator.hasNext()) {
|
||
|
Entry<SoundInstance, ChannelAccess.ChannelHandle> entry = iterator.next();
|
||
|
ChannelAccess.ChannelHandle channelaccess$channelhandle1 = entry.getValue();
|
||
|
SoundInstance soundinstance = entry.getKey();
|
||
|
float f2 = this.options.getSoundSourceVolume(soundinstance.getSource());
|
||
|
if (f2 <= 0.0F) {
|
||
|
channelaccess$channelhandle1.execute(Channel::stop);
|
||
|
iterator.remove();
|
||
|
} else if (channelaccess$channelhandle1.isStopped()) {
|
||
|
int i = this.soundDeleteTime.get(soundinstance);
|
||
|
if (i <= this.tickCount) {
|
||
|
if (shouldLoopManually(soundinstance)) {
|
||
|
this.queuedSounds.put(soundinstance, this.tickCount + soundinstance.getDelay());
|
||
|
}
|
||
|
|
||
|
iterator.remove();
|
||
|
LOGGER.debug(MARKER, "Removed channel {} because it's not playing anymore", channelaccess$channelhandle1);
|
||
|
this.soundDeleteTime.remove(soundinstance);
|
||
|
|
||
|
try {
|
||
|
this.instanceBySource.remove(soundinstance.getSource(), soundinstance);
|
||
|
} catch (RuntimeException runtimeexception) {
|
||
|
}
|
||
|
|
||
|
if (soundinstance instanceof TickableSoundInstance) {
|
||
|
this.tickingSounds.remove(soundinstance);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Iterator<Entry<SoundInstance, Integer>> iterator1 = this.queuedSounds.entrySet().iterator();
|
||
|
|
||
|
while (iterator1.hasNext()) {
|
||
|
Entry<SoundInstance, Integer> entry1 = iterator1.next();
|
||
|
if (this.tickCount >= entry1.getValue()) {
|
||
|
SoundInstance soundinstance1 = entry1.getKey();
|
||
|
if (soundinstance1 instanceof TickableSoundInstance) {
|
||
|
((TickableSoundInstance)soundinstance1).tick();
|
||
|
}
|
||
|
|
||
|
this.play(soundinstance1);
|
||
|
iterator1.remove();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static boolean requiresManualLooping(SoundInstance p_120316_) {
|
||
|
return p_120316_.getDelay() > 0;
|
||
|
}
|
||
|
|
||
|
private static boolean shouldLoopManually(SoundInstance p_120319_) {
|
||
|
return p_120319_.isLooping() && requiresManualLooping(p_120319_);
|
||
|
}
|
||
|
|
||
|
private static boolean shouldLoopAutomatically(SoundInstance p_120322_) {
|
||
|
return p_120322_.isLooping() && !requiresManualLooping(p_120322_);
|
||
|
}
|
||
|
|
||
|
public boolean isActive(SoundInstance p_120306_) {
|
||
|
if (!this.loaded) {
|
||
|
return false;
|
||
|
} else {
|
||
|
return this.soundDeleteTime.containsKey(p_120306_) && this.soundDeleteTime.get(p_120306_) <= this.tickCount ? true : this.instanceToChannel.containsKey(p_120306_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void play(SoundInstance p_120313_) {
|
||
|
if (this.loaded) {
|
||
|
if (p_120313_.canPlaySound()) {
|
||
|
WeighedSoundEvents weighedsoundevents = p_120313_.resolve(this.soundManager);
|
||
|
ResourceLocation resourcelocation = p_120313_.getLocation();
|
||
|
if (weighedsoundevents == null) {
|
||
|
if (ONLY_WARN_ONCE.add(resourcelocation)) {
|
||
|
LOGGER.warn(MARKER, "Unable to play unknown soundEvent: {}", resourcelocation);
|
||
|
}
|
||
|
} else {
|
||
|
Sound sound = p_120313_.getSound();
|
||
|
if (sound != SoundManager.INTENTIONALLY_EMPTY_SOUND) {
|
||
|
if (sound == SoundManager.EMPTY_SOUND) {
|
||
|
if (ONLY_WARN_ONCE.add(resourcelocation)) {
|
||
|
LOGGER.warn(MARKER, "Unable to play empty soundEvent: {}", resourcelocation);
|
||
|
}
|
||
|
} else {
|
||
|
float f = p_120313_.getVolume();
|
||
|
float f1 = Math.max(f, 1.0F) * sound.getAttenuationDistance();
|
||
|
SoundSource soundsource = p_120313_.getSource();
|
||
|
float f2 = this.calculateVolume(f, soundsource);
|
||
|
float f3 = this.calculatePitch(p_120313_);
|
||
|
SoundInstance.Attenuation soundinstance$attenuation = p_120313_.getAttenuation();
|
||
|
boolean flag = p_120313_.isRelative();
|
||
|
if (f2 == 0.0F && !p_120313_.canStartSilent()) {
|
||
|
LOGGER.debug(MARKER, "Skipped playing sound {}, volume was zero.", sound.getLocation());
|
||
|
} else {
|
||
|
Vec3 vec3 = new Vec3(p_120313_.getX(), p_120313_.getY(), p_120313_.getZ());
|
||
|
if (!this.listeners.isEmpty()) {
|
||
|
float f4 = !flag && soundinstance$attenuation != SoundInstance.Attenuation.NONE ? f1 : Float.POSITIVE_INFINITY;
|
||
|
|
||
|
for (SoundEventListener soundeventlistener : this.listeners) {
|
||
|
soundeventlistener.onPlaySound(p_120313_, weighedsoundevents, f4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.listener.getGain() <= 0.0F) {
|
||
|
LOGGER.debug(MARKER, "Skipped playing soundEvent: {}, master volume was zero", resourcelocation);
|
||
|
} else {
|
||
|
boolean flag1 = shouldLoopAutomatically(p_120313_);
|
||
|
boolean flag2 = sound.shouldStream();
|
||
|
CompletableFuture<ChannelAccess.ChannelHandle> completablefuture = this.channelAccess
|
||
|
.createHandle(sound.shouldStream() ? Library.Pool.STREAMING : Library.Pool.STATIC);
|
||
|
ChannelAccess.ChannelHandle channelaccess$channelhandle = completablefuture.join();
|
||
|
if (channelaccess$channelhandle == null) {
|
||
|
if (SharedConstants.IS_RUNNING_IN_IDE) {
|
||
|
LOGGER.warn("Failed to create new sound handle");
|
||
|
}
|
||
|
} else {
|
||
|
LOGGER.debug(MARKER, "Playing sound {} for event {}", sound.getLocation(), resourcelocation);
|
||
|
this.soundDeleteTime.put(p_120313_, this.tickCount + 20);
|
||
|
this.instanceToChannel.put(p_120313_, channelaccess$channelhandle);
|
||
|
this.instanceBySource.put(soundsource, p_120313_);
|
||
|
channelaccess$channelhandle.execute(p_194488_ -> {
|
||
|
p_194488_.setPitch(f3);
|
||
|
p_194488_.setVolume(f2);
|
||
|
if (soundinstance$attenuation == SoundInstance.Attenuation.LINEAR) {
|
||
|
p_194488_.linearAttenuation(f1);
|
||
|
} else {
|
||
|
p_194488_.disableAttenuation();
|
||
|
}
|
||
|
|
||
|
p_194488_.setLooping(flag1 && !flag2);
|
||
|
p_194488_.setSelfPosition(vec3);
|
||
|
p_194488_.setRelative(flag);
|
||
|
});
|
||
|
if (!flag2) {
|
||
|
this.soundBuffers
|
||
|
.getCompleteBuffer(sound.getPath())
|
||
|
.thenAccept(p_377326_ -> channelaccess$channelhandle.execute(p_194495_ -> {
|
||
|
p_194495_.attachStaticBuffer(p_377326_);
|
||
|
p_194495_.play();
|
||
|
}));
|
||
|
} else {
|
||
|
this.soundBuffers
|
||
|
.getStream(sound.getPath(), flag1)
|
||
|
.thenAccept(p_376862_ -> channelaccess$channelhandle.execute(p_194498_ -> {
|
||
|
p_194498_.attachBufferStream(p_376862_);
|
||
|
p_194498_.play();
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
if (p_120313_ instanceof TickableSoundInstance) {
|
||
|
this.tickingSounds.add((TickableSoundInstance)p_120313_);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void queueTickingSound(TickableSoundInstance p_120283_) {
|
||
|
this.queuedTickableSounds.add(p_120283_);
|
||
|
}
|
||
|
|
||
|
public void requestPreload(Sound p_120273_) {
|
||
|
this.preloadQueue.add(p_120273_);
|
||
|
}
|
||
|
|
||
|
private float calculatePitch(SoundInstance p_120325_) {
|
||
|
return Mth.clamp(p_120325_.getPitch(), 0.5F, 2.0F);
|
||
|
}
|
||
|
|
||
|
private float calculateVolume(SoundInstance p_120328_) {
|
||
|
return this.calculateVolume(p_120328_.getVolume(), p_120328_.getSource());
|
||
|
}
|
||
|
|
||
|
private float calculateVolume(float p_235258_, SoundSource p_235259_) {
|
||
|
return Mth.clamp(p_235258_ * this.getVolume(p_235259_), 0.0F, 1.0F);
|
||
|
}
|
||
|
|
||
|
public void pause() {
|
||
|
if (this.loaded) {
|
||
|
this.channelAccess.executeOnChannels(p_194510_ -> p_194510_.forEach(Channel::pause));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void resume() {
|
||
|
if (this.loaded) {
|
||
|
this.channelAccess.executeOnChannels(p_194508_ -> p_194508_.forEach(Channel::unpause));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void playDelayed(SoundInstance p_120277_, int p_120278_) {
|
||
|
this.queuedSounds.put(p_120277_, this.tickCount + p_120278_);
|
||
|
}
|
||
|
|
||
|
public void updateSource(Camera p_120271_) {
|
||
|
if (this.loaded && p_120271_.isInitialized()) {
|
||
|
ListenerTransform listenertransform = new ListenerTransform(p_120271_.getPosition(), new Vec3(p_120271_.getLookVector()), new Vec3(p_120271_.getUpVector()));
|
||
|
this.executor.execute(() -> this.listener.setTransform(listenertransform));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void stop(@Nullable ResourceLocation p_120300_, @Nullable SoundSource p_120301_) {
|
||
|
if (p_120301_ != null) {
|
||
|
for (SoundInstance soundinstance : this.instanceBySource.get(p_120301_)) {
|
||
|
if (p_120300_ == null || soundinstance.getLocation().equals(p_120300_)) {
|
||
|
this.stop(soundinstance);
|
||
|
}
|
||
|
}
|
||
|
} else if (p_120300_ == null) {
|
||
|
this.stopAll();
|
||
|
} else {
|
||
|
for (SoundInstance soundinstance1 : this.instanceToChannel.keySet()) {
|
||
|
if (soundinstance1.getLocation().equals(p_120300_)) {
|
||
|
this.stop(soundinstance1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public String getDebugString() {
|
||
|
return this.library.getDebugString();
|
||
|
}
|
||
|
|
||
|
public List<String> getAvailableSoundDevices() {
|
||
|
return this.library.getAvailableSoundDevices();
|
||
|
}
|
||
|
|
||
|
public ListenerTransform getListenerTransform() {
|
||
|
return this.listener.getTransform();
|
||
|
}
|
||
|
|
||
|
@OnlyIn(Dist.CLIENT)
|
||
|
static enum DeviceCheckState {
|
||
|
ONGOING,
|
||
|
CHANGE_DETECTED,
|
||
|
NO_CHANGE;
|
||
|
}
|
||
|
}
|