SoundManager.java

net.minecraft.client.sounds.SoundManager

信息

  • 全限定名:net.minecraft.client.sounds.SoundManager
  • 类型:public class
  • 包:net.minecraft.client.sounds
  • 源码路径:src/main/java/net/minecraft/client/sounds/SoundManager.java
  • 起始行号:L45
  • 继承:SimplePreparableReloadListener<SoundManager.Preparations>
  • 职责:

    TODO

字段/常量

  • EMPTY_SOUND_LOCATION

    • 类型: Identifier
    • 修饰符: public static final
    • 源码定位: L46
    • 说明:

      TODO

  • EMPTY_SOUND

    • 类型: Sound
    • 修饰符: public static final
    • 源码定位: L47
    • 说明:

      TODO

  • INTENTIONALLY_EMPTY_SOUND_LOCATION

    • 类型: Identifier
    • 修饰符: public static final
    • 源码定位: L50
    • 说明:

      TODO

  • INTENTIONALLY_EMPTY_SOUND_EVENT

    • 类型: WeighedSoundEvents
    • 修饰符: public static final
    • 源码定位: L51
    • 说明:

      TODO

  • INTENTIONALLY_EMPTY_SOUND

    • 类型: Sound
    • 修饰符: public static final
    • 源码定位: L52
    • 说明:

      TODO

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L55
    • 说明:

      TODO

  • SOUNDS_PATH

    • 类型: String
    • 修饰符: private static final
    • 源码定位: L56
    • 说明:

      TODO

  • GSON

    • 类型: Gson
    • 修饰符: private static final
    • 源码定位: L57
    • 说明:

      TODO

  • SOUND_EVENT_REGISTRATION_TYPE

    • 类型: TypeToken<Map<String,SoundEventRegistration>>
    • 修饰符: private static final
    • 源码定位: L58
    • 说明:

      TODO

  • registry

    • 类型: Map<Identifier,WeighedSoundEvents>
    • 修饰符: private final
    • 源码定位: L59
    • 说明:

      TODO

  • soundEngine

    • 类型: SoundEngine
    • 修饰符: private final
    • 源码定位: L60
    • 说明:

      TODO

  • soundCache

    • 类型: Map<Identifier,Resource>
    • 修饰符: private final
    • 源码定位: L61
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.sounds.SoundManager.Preparations
    • 类型: class
    • 修饰符: protected static
    • 源码定位: L231
    • 说明:

      TODO

构造器

public SoundManager(Options options) @ L63

  • 构造器名:SoundManager
  • 源码定位:L63
  • 修饰符:public

参数:

  • options: Options

说明:

TODO

方法

下面的方法块按源码顺序生成。

protected SoundManager.Preparations prepare(ResourceManager manager, ProfilerFiller profiler) @ L67

  • 方法名:prepare
  • 源码定位:L67
  • 返回类型:SoundManager.Preparations
  • 修饰符:protected

参数:

  • manager: ResourceManager
  • profiler: ProfilerFiller

说明:

TODO

protected void apply(SoundManager.Preparations preparations, ResourceManager manager, ProfilerFiller profiler) @ L102

  • 方法名:apply
  • 源码定位:L102
  • 返回类型:void
  • 修饰符:protected

参数:

  • preparations: SoundManager.Preparations
  • manager: ResourceManager
  • profiler: ProfilerFiller

说明:

TODO

public List<String> getAvailableSoundDevices() @ L124

  • 方法名:getAvailableSoundDevices
  • 源码定位:L124
  • 返回类型:List
  • 修饰符:public

参数:

说明:

TODO

public ListenerTransform getListenerTransform() @ L128

  • 方法名:getListenerTransform
  • 源码定位:L128
  • 返回类型:ListenerTransform
  • 修饰符:public

参数:

说明:

TODO

private static boolean validateSoundResource(Sound sound, Identifier eventLocation, ResourceProvider resourceProvider) @ L132

  • 方法名:validateSoundResource
  • 源码定位:L132
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • sound: Sound
  • eventLocation: Identifier
  • resourceProvider: ResourceProvider

说明:

TODO

public WeighedSoundEvents getSoundEvent(Identifier location) @ L142

  • 方法名:getSoundEvent
  • 源码定位:L142
  • 返回类型:WeighedSoundEvents
  • 修饰符:public

参数:

  • location: Identifier

说明:

TODO

public Collection<Identifier> getAvailableSounds() @ L146

  • 方法名:getAvailableSounds
  • 源码定位:L146
  • 返回类型:Collection
  • 修饰符:public

参数:

说明:

TODO

public void queueTickingSound(TickableSoundInstance instance) @ L150

  • 方法名:queueTickingSound
  • 源码定位:L150
  • 返回类型:void
  • 修饰符:public

参数:

  • instance: TickableSoundInstance

说明:

TODO

public SoundEngine.PlayResult play(SoundInstance instance) @ L154

  • 方法名:play
  • 源码定位:L154
  • 返回类型:SoundEngine.PlayResult
  • 修饰符:public

参数:

  • instance: SoundInstance

说明:

TODO

public void playDelayed(SoundInstance instance, int delay) @ L158

  • 方法名:playDelayed
  • 源码定位:L158
  • 返回类型:void
  • 修饰符:public

参数:

  • instance: SoundInstance
  • delay: int

说明:

TODO

public void updateSource(Camera camera) @ L162

  • 方法名:updateSource
  • 源码定位:L162
  • 返回类型:void
  • 修饰符:public

参数:

  • camera: Camera

说明:

TODO

public void pauseAllExcept(SoundSource... ignoredSources) @ L166

  • 方法名:pauseAllExcept
  • 源码定位:L166
  • 返回类型:void
  • 修饰符:public

参数:

  • ignoredSources: SoundSource…

说明:

TODO

public void stop() @ L170

  • 方法名:stop
  • 源码定位:L170
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void destroy() @ L174

  • 方法名:destroy
  • 源码定位:L174
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void emergencyShutdown() @ L178

  • 方法名:emergencyShutdown
  • 源码定位:L178
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void tick(boolean paused) @ L182

  • 方法名:tick
  • 源码定位:L182
  • 返回类型:void
  • 修饰符:public

参数:

  • paused: boolean

说明:

TODO

public void resume() @ L186

  • 方法名:resume
  • 源码定位:L186
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void refreshCategoryVolume(SoundSource category) @ L190

  • 方法名:refreshCategoryVolume
  • 源码定位:L190
  • 返回类型:void
  • 修饰符:public

参数:

  • category: SoundSource

说明:

TODO

public void stop(SoundInstance soundInstance) @ L194

  • 方法名:stop
  • 源码定位:L194
  • 返回类型:void
  • 修饰符:public

参数:

  • soundInstance: SoundInstance

说明:

TODO

public void updateCategoryVolume(SoundSource source, float gain) @ L198

  • 方法名:updateCategoryVolume
  • 源码定位:L198
  • 返回类型:void
  • 修饰符:public

参数:

  • source: SoundSource
  • gain: float

说明:

TODO

public boolean isActive(SoundInstance instance) @ L202

  • 方法名:isActive
  • 源码定位:L202
  • 返回类型:boolean
  • 修饰符:public

参数:

  • instance: SoundInstance

说明:

TODO

public void addListener(SoundEventListener listener) @ L206

  • 方法名:addListener
  • 源码定位:L206
  • 返回类型:void
  • 修饰符:public

参数:

  • listener: SoundEventListener

说明:

TODO

public void removeListener(SoundEventListener listener) @ L210

  • 方法名:removeListener
  • 源码定位:L210
  • 返回类型:void
  • 修饰符:public

参数:

  • listener: SoundEventListener

说明:

TODO

public void stop(Identifier sound, SoundSource source) @ L214

  • 方法名:stop
  • 源码定位:L214
  • 返回类型:void
  • 修饰符:public

参数:

  • sound: Identifier
  • source: SoundSource

说明:

TODO

public String getChannelDebugString() @ L218

  • 方法名:getChannelDebugString
  • 源码定位:L218
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

public void getSoundCacheDebugStats(SoundBufferLibrary.DebugOutput output) @ L222

  • 方法名:getSoundCacheDebugStats
  • 源码定位:L222
  • 返回类型:void
  • 修饰符:public

参数:

  • output: SoundBufferLibrary.DebugOutput

说明:

TODO

public void reload() @ L226

  • 方法名:reload
  • 源码定位:L226
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class SoundManager extends SimplePreparableReloadListener<SoundManager.Preparations> {
    public static final Identifier EMPTY_SOUND_LOCATION = Identifier.withDefaultNamespace("empty");
    public static final Sound EMPTY_SOUND = new Sound(
        EMPTY_SOUND_LOCATION, ConstantFloat.of(1.0F), ConstantFloat.of(1.0F), 1, Sound.Type.FILE, false, false, 16
    );
    public static final Identifier INTENTIONALLY_EMPTY_SOUND_LOCATION = Identifier.withDefaultNamespace("intentionally_empty");
    public static final WeighedSoundEvents INTENTIONALLY_EMPTY_SOUND_EVENT = new WeighedSoundEvents(INTENTIONALLY_EMPTY_SOUND_LOCATION, null);
    public static final Sound INTENTIONALLY_EMPTY_SOUND = new Sound(
        INTENTIONALLY_EMPTY_SOUND_LOCATION, ConstantFloat.of(1.0F), ConstantFloat.of(1.0F), 1, Sound.Type.FILE, false, false, 16
    );
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final String SOUNDS_PATH = "sounds.json";
    private static final Gson GSON = new GsonBuilder().registerTypeAdapter(SoundEventRegistration.class, new SoundEventRegistrationSerializer()).create();
    private static final TypeToken<Map<String, SoundEventRegistration>> SOUND_EVENT_REGISTRATION_TYPE = new TypeToken<Map<String, SoundEventRegistration>>() {};
    private final Map<Identifier, WeighedSoundEvents> registry = Maps.newHashMap();
    private final SoundEngine soundEngine;
    private final Map<Identifier, Resource> soundCache = new HashMap<>();
 
    public SoundManager(Options options) {
        this.soundEngine = new SoundEngine(this, options, ResourceProvider.fromMap(this.soundCache));
    }
 
    protected SoundManager.Preparations prepare(ResourceManager manager, ProfilerFiller profiler) {
        SoundManager.Preparations preparations = new SoundManager.Preparations();
 
        try (Zone ignored = profiler.zone("list")) {
            preparations.listResources(manager);
        }
 
        for (String namespace : manager.getNamespaces()) {
            try (Zone ignored = profiler.zone(namespace)) {
                for (Resource resource : manager.getResourceStack(Identifier.fromNamespaceAndPath(namespace, "sounds.json"))) {
                    profiler.push(resource.sourcePackId());
 
                    try (Reader reader = resource.openAsReader()) {
                        profiler.push("parse");
                        Map<String, SoundEventRegistration> map = GsonHelper.fromJson(GSON, reader, SOUND_EVENT_REGISTRATION_TYPE);
                        profiler.popPush("register");
 
                        for (Entry<String, SoundEventRegistration> entry : map.entrySet()) {
                            preparations.handleRegistration(Identifier.fromNamespaceAndPath(namespace, entry.getKey()), entry.getValue());
                        }
 
                        profiler.pop();
                    } catch (RuntimeException var19) {
                        LOGGER.warn("Invalid {} in resourcepack: '{}'", "sounds.json", resource.sourcePackId(), var19);
                    }
 
                    profiler.pop();
                }
            } catch (IOException var21) {
            }
        }
 
        return preparations;
    }
 
    protected void apply(SoundManager.Preparations preparations, ResourceManager manager, ProfilerFiller profiler) {
        preparations.apply(this.registry, this.soundCache, this.soundEngine);
        if (SharedConstants.IS_RUNNING_IN_IDE) {
            for (Identifier location : this.registry.keySet()) {
                WeighedSoundEvents event = this.registry.get(location);
                if (!ComponentUtils.isTranslationResolvable(event.getSubtitle()) && BuiltInRegistries.SOUND_EVENT.containsKey(location)) {
                    LOGGER.error("Missing subtitle {} for sound event: {}", event.getSubtitle(), location);
                }
            }
        }
 
        if (LOGGER.isDebugEnabled()) {
            for (Identifier locationx : this.registry.keySet()) {
                if (!BuiltInRegistries.SOUND_EVENT.containsKey(locationx)) {
                    LOGGER.debug("Not having sound event for: {}", locationx);
                }
            }
        }
 
        this.soundEngine.reload();
    }
 
    public List<String> getAvailableSoundDevices() {
        return this.soundEngine.getAvailableSoundDevices();
    }
 
    public ListenerTransform getListenerTransform() {
        return this.soundEngine.getListenerTransform();
    }
 
    private static boolean validateSoundResource(Sound sound, Identifier eventLocation, ResourceProvider resourceProvider) {
        Identifier soundPath = sound.getPath();
        if (resourceProvider.getResource(soundPath).isEmpty()) {
            LOGGER.warn("File {} does not exist, cannot add it to event {}", soundPath, eventLocation);
            return false;
        } else {
            return true;
        }
    }
 
    public @Nullable WeighedSoundEvents getSoundEvent(Identifier location) {
        return this.registry.get(location);
    }
 
    public Collection<Identifier> getAvailableSounds() {
        return this.registry.keySet();
    }
 
    public void queueTickingSound(TickableSoundInstance instance) {
        this.soundEngine.queueTickingSound(instance);
    }
 
    public SoundEngine.PlayResult play(SoundInstance instance) {
        return this.soundEngine.play(instance);
    }
 
    public void playDelayed(SoundInstance instance, int delay) {
        this.soundEngine.playDelayed(instance, delay);
    }
 
    public void updateSource(Camera camera) {
        this.soundEngine.updateSource(camera);
    }
 
    public void pauseAllExcept(SoundSource... ignoredSources) {
        this.soundEngine.pauseAllExcept(ignoredSources);
    }
 
    public void stop() {
        this.soundEngine.stopAll();
    }
 
    public void destroy() {
        this.soundEngine.destroy();
    }
 
    public void emergencyShutdown() {
        this.soundEngine.emergencyShutdown();
    }
 
    public void tick(boolean paused) {
        this.soundEngine.tick(paused);
    }
 
    public void resume() {
        this.soundEngine.resume();
    }
 
    public void refreshCategoryVolume(SoundSource category) {
        this.soundEngine.refreshCategoryVolume(category);
    }
 
    public void stop(SoundInstance soundInstance) {
        this.soundEngine.stop(soundInstance);
    }
 
    public void updateCategoryVolume(SoundSource source, float gain) {
        this.soundEngine.updateCategoryVolume(source, gain);
    }
 
    public boolean isActive(SoundInstance instance) {
        return this.soundEngine.isActive(instance);
    }
 
    public void addListener(SoundEventListener listener) {
        this.soundEngine.addEventListener(listener);
    }
 
    public void removeListener(SoundEventListener listener) {
        this.soundEngine.removeEventListener(listener);
    }
 
    public void stop(@Nullable Identifier sound, @Nullable SoundSource source) {
        this.soundEngine.stop(sound, source);
    }
 
    public String getChannelDebugString() {
        return this.soundEngine.getChannelDebugString();
    }
 
    public void getSoundCacheDebugStats(SoundBufferLibrary.DebugOutput output) {
        this.soundEngine.getSoundCacheDebugStats(output);
    }
 
    public void reload() {
        this.soundEngine.reload();
    }
 
    @OnlyIn(Dist.CLIENT)
    protected static class Preparations {
        private final Map<Identifier, WeighedSoundEvents> registry = Maps.newHashMap();
        private Map<Identifier, Resource> soundCache = Map.of();
 
        private void listResources(ResourceManager resourceManager) {
            this.soundCache = Sound.SOUND_LISTER.listMatchingResources(resourceManager);
        }
 
        private void handleRegistration(Identifier eventLocation, SoundEventRegistration soundEventRegistration) {
            WeighedSoundEvents registration = this.registry.get(eventLocation);
            boolean missesRegistration = registration == null;
            if (missesRegistration || soundEventRegistration.isReplace()) {
                if (!missesRegistration) {
                    SoundManager.LOGGER.debug("Replaced sound event location {}", eventLocation);
                }
 
                registration = new WeighedSoundEvents(eventLocation, soundEventRegistration.getSubtitle());
                this.registry.put(eventLocation, registration);
            }
 
            ResourceProvider cachedProvider = ResourceProvider.fromMap(this.soundCache);
 
            for (final Sound sound : soundEventRegistration.getSounds()) {
                final Identifier soundLocation = sound.getLocation();
                Weighted<Sound> weighted;
                switch (sound.getType()) {
                    case FILE:
                        if (!SoundManager.validateSoundResource(sound, eventLocation, cachedProvider)) {
                            continue;
                        }
 
                        weighted = sound;
                        break;
                    case SOUND_EVENT:
                        weighted = new Weighted<Sound>() {
                            {
                                Objects.requireNonNull(Preparations.this);
                            }
 
                            @Override
                            public int getWeight() {
                                WeighedSoundEvents registrationx = Preparations.this.registry.get(soundLocation);
                                return registrationx == null ? 0 : registrationx.getWeight();
                            }
 
                            public Sound getSound(RandomSource random) {
                                WeighedSoundEvents registrationx = Preparations.this.registry.get(soundLocation);
                                if (registrationx == null) {
                                    return SoundManager.EMPTY_SOUND;
                                } else {
                                    Sound wrappedSound = registrationx.getSound(random);
                                    return new Sound(
                                        wrappedSound.getLocation(),
                                        new MultipliedFloats(wrappedSound.getVolume(), sound.getVolume()),
                                        new MultipliedFloats(wrappedSound.getPitch(), sound.getPitch()),
                                        sound.getWeight(),
                                        Sound.Type.FILE,
                                        wrappedSound.shouldStream() || sound.shouldStream(),
                                        wrappedSound.shouldPreload(),
                                        wrappedSound.getAttenuationDistance()
                                    );
                                }
                            }
 
                            @Override
                            public void preloadIfRequired(SoundEngine soundEngine) {
                                WeighedSoundEvents registrationx = Preparations.this.registry.get(soundLocation);
                                if (registrationx != null) {
                                    registrationx.preloadIfRequired(soundEngine);
                                }
                            }
                        };
                        break;
                    default:
                        throw new IllegalStateException("Unknown SoundEventRegistration type: " + sound.getType());
                }
 
                registration.addSound(weighted);
            }
        }
 
        public void apply(Map<Identifier, WeighedSoundEvents> registry, Map<Identifier, Resource> soundCache, SoundEngine engine) {
            registry.clear();
            soundCache.clear();
            soundCache.putAll(this.soundCache);
 
            for (Entry<Identifier, WeighedSoundEvents> entry : this.registry.entrySet()) {
                registry.put(entry.getKey(), entry.getValue());
                entry.getValue().preloadIfRequired(engine);
            }
        }
    }
}

引用的其他类