227 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.sounds;
 | |
| 
 | |
| import com.mojang.serialization.Codec;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.client.Minecraft;
 | |
| import net.minecraft.client.resources.sounds.SimpleSoundInstance;
 | |
| import net.minecraft.client.resources.sounds.Sound;
 | |
| import net.minecraft.client.resources.sounds.SoundInstance;
 | |
| import net.minecraft.sounds.Music;
 | |
| import net.minecraft.sounds.SoundEvent;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.util.OptionEnum;
 | |
| import net.minecraft.util.RandomSource;
 | |
| import net.minecraft.util.StringRepresentable;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| /**
 | |
|  * The MusicManager class manages the playing of music in Minecraft.
 | |
|  */
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class MusicManager {
 | |
| 	/**
 | |
| 	 * The delay before starting to play the next song.
 | |
| 	 */
 | |
| 	private static final int STARTING_DELAY = 100;
 | |
| 	private final RandomSource random = RandomSource.create();
 | |
| 	private final Minecraft minecraft;
 | |
| 	@Nullable
 | |
| 	private SoundInstance currentMusic;
 | |
| 	private MusicManager.MusicFrequency gameMusicFrequency;
 | |
| 	private float currentGain = 1.0F;
 | |
| 	/**
 | |
| 	 * The delay until the next song starts.
 | |
| 	 */
 | |
| 	private int nextSongDelay = 100;
 | |
| 	private boolean toastShown = false;
 | |
| 
 | |
| 	public MusicManager(Minecraft minecraft) {
 | |
| 		this.minecraft = minecraft;
 | |
| 		this.gameMusicFrequency = minecraft.options.musicFrequency().get();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Called every tick to manage the playing of music.
 | |
| 	 */
 | |
| 	public void tick() {
 | |
| 		MusicInfo musicInfo = this.minecraft.getSituationalMusic();
 | |
| 		float f = musicInfo.volume();
 | |
| 		if (this.currentMusic != null && this.currentGain != f) {
 | |
| 			boolean bl = this.fadePlaying(f);
 | |
| 			if (!bl) {
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		Music music = musicInfo.music();
 | |
| 		if (music == null) {
 | |
| 			this.nextSongDelay = Math.max(this.nextSongDelay, 100);
 | |
| 		} else {
 | |
| 			if (this.currentMusic != null) {
 | |
| 				if (musicInfo.canReplace(this.currentMusic)) {
 | |
| 					this.minecraft.getSoundManager().stop(this.currentMusic);
 | |
| 					this.nextSongDelay = Mth.nextInt(this.random, 0, music.minDelay() / 2);
 | |
| 				}
 | |
| 
 | |
| 				if (!this.minecraft.getSoundManager().isActive(this.currentMusic)) {
 | |
| 					this.currentMusic = null;
 | |
| 					this.nextSongDelay = Math.min(this.nextSongDelay, this.gameMusicFrequency.getNextSongDelay(music, this.random));
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			this.nextSongDelay = Math.min(this.nextSongDelay, this.gameMusicFrequency.getNextSongDelay(music, this.random));
 | |
| 			if (this.currentMusic == null && this.nextSongDelay-- <= 0) {
 | |
| 				this.startPlaying(musicInfo);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void startPlaying(MusicInfo music) {
 | |
| 		SoundEvent soundEvent = music.music().event().value();
 | |
| 		this.currentMusic = SimpleSoundInstance.forMusic(soundEvent, music.volume());
 | |
| 		switch (this.minecraft.getSoundManager().play(this.currentMusic)) {
 | |
| 			case STARTED:
 | |
| 				this.minecraft.getToastManager().showNowPlayingToast();
 | |
| 				this.toastShown = true;
 | |
| 				break;
 | |
| 			case STARTED_SILENTLY:
 | |
| 				this.toastShown = false;
 | |
| 		}
 | |
| 
 | |
| 		this.nextSongDelay = Integer.MAX_VALUE;
 | |
| 		this.currentGain = music.volume();
 | |
| 	}
 | |
| 
 | |
| 	public void showNowPlayingToastIfNeeded() {
 | |
| 		if (!this.toastShown) {
 | |
| 			this.minecraft.getToastManager().showNowPlayingToast();
 | |
| 			this.toastShown = true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Stops playing the specified {@linkplain Music} selector.
 | |
| 	 * 
 | |
| 	 * @param music the {@linkplain Music} selector to stop playing
 | |
| 	 */
 | |
| 	public void stopPlaying(Music music) {
 | |
| 		if (this.isPlayingMusic(music)) {
 | |
| 			this.stopPlaying();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Stops playing the current {@linkplain Music} selector.
 | |
| 	 */
 | |
| 	public void stopPlaying() {
 | |
| 		if (this.currentMusic != null) {
 | |
| 			this.minecraft.getSoundManager().stop(this.currentMusic);
 | |
| 			this.currentMusic = null;
 | |
| 			this.minecraft.getToastManager().hideNowPlayingToast();
 | |
| 		}
 | |
| 
 | |
| 		this.nextSongDelay += 100;
 | |
| 	}
 | |
| 
 | |
| 	private boolean fadePlaying(float volume) {
 | |
| 		if (this.currentMusic == null) {
 | |
| 			return false;
 | |
| 		} else if (this.currentGain == volume) {
 | |
| 			return true;
 | |
| 		} else {
 | |
| 			if (this.currentGain < volume) {
 | |
| 				this.currentGain = this.currentGain + Mth.clamp(this.currentGain, 5.0E-4F, 0.005F);
 | |
| 				if (this.currentGain > volume) {
 | |
| 					this.currentGain = volume;
 | |
| 				}
 | |
| 			} else {
 | |
| 				this.currentGain = 0.03F * volume + 0.97F * this.currentGain;
 | |
| 				if (Math.abs(this.currentGain - volume) < 1.0E-4F || this.currentGain < volume) {
 | |
| 					this.currentGain = volume;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			this.currentGain = Mth.clamp(this.currentGain, 0.0F, 1.0F);
 | |
| 			if (this.currentGain <= 1.0E-4F) {
 | |
| 				this.stopPlaying();
 | |
| 				return false;
 | |
| 			} else {
 | |
| 				this.minecraft.getSoundManager().setVolume(this.currentMusic, this.currentGain);
 | |
| 				return true;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * {@return {@code true} if the {@linkplain Music} selector is currently playing, {@code false} otherwise}
 | |
| 	 * 
 | |
| 	 * @param selector the {@linkplain Music} selector to check for
 | |
| 	 */
 | |
| 	public boolean isPlayingMusic(Music selector) {
 | |
| 		return this.currentMusic == null ? false : selector.event().value().location().equals(this.currentMusic.getLocation());
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public String getCurrentMusicTranslationKey() {
 | |
| 		if (this.currentMusic != null) {
 | |
| 			Sound sound = this.currentMusic.getSound();
 | |
| 			if (sound != null) {
 | |
| 				return sound.getLocation().toShortLanguageKey();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return null;
 | |
| 	}
 | |
| 
 | |
| 	public void setMinutesBetweenSongs(MusicManager.MusicFrequency musicFrequency) {
 | |
| 		this.gameMusicFrequency = musicFrequency;
 | |
| 		this.nextSongDelay = this.gameMusicFrequency.getNextSongDelay(this.minecraft.getSituationalMusic().music(), this.random);
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public static enum MusicFrequency implements OptionEnum, StringRepresentable {
 | |
| 		DEFAULT(20),
 | |
| 		FREQUENT(10),
 | |
| 		CONSTANT(0);
 | |
| 
 | |
| 		public static final Codec<MusicManager.MusicFrequency> CODEC = StringRepresentable.fromEnum(MusicManager.MusicFrequency::values);
 | |
| 		private static final String KEY_PREPEND = "options.music_frequency.";
 | |
| 		private final int id;
 | |
| 		private final int maxFrequency;
 | |
| 		private final String key;
 | |
| 
 | |
| 		private MusicFrequency(final int maxFrequency) {
 | |
| 			this.id = maxFrequency;
 | |
| 			this.maxFrequency = maxFrequency * 1200;
 | |
| 			this.key = "options.music_frequency." + this.name().toLowerCase();
 | |
| 		}
 | |
| 
 | |
| 		int getNextSongDelay(@Nullable Music music, RandomSource random) {
 | |
| 			if (music == null) {
 | |
| 				return this.maxFrequency;
 | |
| 			} else if (this == CONSTANT) {
 | |
| 				return 100;
 | |
| 			} else {
 | |
| 				int i = Math.min(music.minDelay(), this.maxFrequency);
 | |
| 				int j = Math.min(music.maxDelay(), this.maxFrequency);
 | |
| 				return Mth.nextInt(random, i, j);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public int getId() {
 | |
| 			return this.id;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public String getKey() {
 | |
| 			return this.key;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public String getSerializedName() {
 | |
| 			return this.name();
 | |
| 		}
 | |
| 	}
 | |
| }
 |