Jump to content

Adding additional SoundCategory(s)


Aeronica

Recommended Posts

I'm looking for some help to get this added as a proper PR to forge. I have a working class for adding the sound category that will work in a mod. I've tested this with with 1.9.4 and 1.10+. I have not yet tried to setup a Forge dev environment but the videos that cpw made make it look simple enough. I still pretty much a java rookies, but learning more as I go. Your comments are welcome.

 

The class below allows the addition of a new sound category. It uses nothing more that the existing Forge utility classes for reflections and enums. You new sound category will have all the attributes of the vanilla sound categories.

That is:

  • A volume control for the category displays in the vanilla "Music & Sound Options..." dialog
  • The volume level is saved and loaded from the client options.txt file.
  • The Vanilla SoundHandler will correctly use the custom sound category

Here's the class on GitHub. There are some notes about using it in the comments

MODSoundCategory

I've also included the code below.

 

I have not started work to see what's required to make the vanilla "Music & Sound Options..." dialog behave correctly. Ideally it would work like the "Controls..." dialog. That is the volume controls could be scrolled. So far I've not seen anyone other mod add a custom SoundCategory / volume control. But it might be useful for other mods. And as a part of Forge mod authors could use it without fear of causing issues with vanilla or other mods.

 

For the mxTune mod I'm working on I wanted a separate sound category for the instruments. I can get by without this PR, but I wanted to share this with the community.

 

MODSoundCategory.class

 

package net.aeronica.mods.mxtune.sound;

import java.util.Map;

import com.google.common.collect.Maps;

import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.SoundCategory;
import net.minecraftforge.common.util.EnumHelper;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.relauncher.FMLLaunchHandler;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

/*
* MODSoundCategory
* 
* Add a new CONSTANT and reference name to net.minecraft.util.SoundCategory
* 
* This allows the display of a volume control in the "Music & Sound Options" dialog.
* Unfortunately the GuiScreenOptionsSounds dialog does not auto size
* properly and move the Done button lower on the screen.
* 
* To initialize the class create an instance during FMLPreInitializationEvent in
* the file with the @Mod annotation or your common proxy class.
* 
* Usage example: static final SoundCategory SC_MXTUNE = MODSoundCategory.add("MXTUNE");
* 
* The language file key is "soundCategory.mxtune"
* The game settings "options.txt" key is "soundCategory_mxtune"
* 
* To use the MXTUNE enum constant in code it must be referenced by name because
* SoundCategory.MXTUNE does not exist at compile time.
*   e.g. SoundCategory.getByName("mxtune");
* 
* @author Paul Boese aka Aeronica
*
*/
public class MODSoundCategory
{
    
    private static final String SRG_soundLevels = "field_186714_aM";
    private static final String SRG_SOUND_CATEGORIES = "field_187961_k";
    private static Map<SoundCategory, Float> soundLevels;
    private static MODSoundCategory instance = new MODSoundCategory();
    
    private MODSoundCategory() {}
    
    public static MODSoundCategory getInstance() {return instance;}
    
    /**
     * The "name" should be your MODID or MODID_name if your mod adds more
     * than one SoundCategory.
     * 
     * @param name
     * @return a unique SoundCategory
     * @throws fatal error if name is not unique
     */    
    public static SoundCategory add(String name)
    {
        Map<String, SoundCategory> SOUND_CATEGORIES;

        String constantName;
        String referenceName;
        SoundCategory soundCategory;
        constantName = new String(name.toUpperCase().replace(" ", ""));
        referenceName = new String(constantName.toLowerCase());
        soundCategory =  EnumHelper.addEnum(SoundCategory.class , constantName, new Class[]{String.class}, new Object[]{referenceName});
        SOUND_CATEGORIES = ObfuscationReflectionHelper.getPrivateValue(SoundCategory.class, SoundCategory.VOICE ,"SOUND_CATEGORIES", SRG_SOUND_CATEGORIES);
        if (SOUND_CATEGORIES.containsKey(referenceName))
            throw new Error("Clash in Sound Category name pools! Cannot insert " + constantName);
        SOUND_CATEGORIES.put(referenceName, soundCategory);
        if (FMLLaunchHandler.side() == Side.CLIENT) setSoundLevels();

        return soundCategory;
    }

    /** Game sound level options settings only exist on the client side */
    @SideOnly(Side.CLIENT)
    private static void setSoundLevels()
    {
        /** SoundCategory now contains 'name' sound category so build a new map */
        soundLevels = Maps.newEnumMap(SoundCategory.class);
        /** Replace the map in the GameSettings.class */
        ObfuscationReflectionHelper.setPrivateValue(GameSettings.class, Minecraft.getMinecraft().gameSettings, soundLevels, "soundLevels", SRG_soundLevels);
    }

}

 

From this point on I'll just use bare bones minimal/incomplete code...

Creating custom sound categories:

 

 

package net.aeronica.mods.modtest;

import net.aeronica.mods.mod189stuff.audio.MODSoundCategory;
import net.aeronica.mods.mod189stuff.caps.ISimple;
import net.minecraft.util.SoundCategory;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

@Mod(modid = Main.MODID, name = Main.MODNAME, version = Main.VERSION)
public class Main {
public static final String MODID = "modtest";
public static final String MODNAME = "Mod Testing";
public static final String VERSION = "1.10.2-0.1.0-dev";

@Mod.Instance(MODID)
public static Main instance;

public static SoundCategory MODTEST_A;
public static SoundCategory MODTEST_B;
public static SoundCategory MODTEST_C;
public static SoundCategory MODTEST_D;
public static SoundCategory MODTEST_E;
public static SoundCategory MODTEST_F;
public static SoundCategory MODTEST_G;
public static SoundCategory MODTEST_H;

@EventHandler
public void preInit(FMLPreInitializationEvent event) {
        // You need to register these on the the client and server side. A good place is your common proxy.
MODTEST_A = MODSoundCategory.add("MODTEST_A");
        MODTEST_B = MODSoundCategory.add("MODTEST_B");
        MODTEST_C = MODSoundCategory.add("MODTEST_C");
        MODTEST_D = MODSoundCategory.add("MODTEST_D");
        MODTEST_E = MODSoundCategory.add("MODTEST_E");
        MODTEST_F = MODSoundCategory.add("MODTEST_F");
        MODTEST_G = MODSoundCategory.add("MODTEST_G");
        MODTEST_H = MODSoundCategory.add("MODTEST_H");
}

@EventHandler
public void init(FMLInitializationEvent event) {
}

@EventHandler
public void postInit(FMLPostInitializationEvent event) {
}

}

 

Here's one way to use the custom sound category

 

// some item
. . .
    @Override
    public ActionResult<ItemStack> onItemRightClick(ItemStack itemStackIn, World worldIn, EntityPlayer playerIn, EnumHand hand)
    {
        if (!worldIn.isRemote)
        {
            // worldIn.playSound(EntityPlayer, BlockPos, SoundEvent, SoundCategory, volume, pitch)
            worldIn.playSound(null, new BlockPos(playerIn.posX,playerIn.posY,playerIn.posZ), 
                    SoundEvents.ENTITY_FIREWORK_BLAST, SoundCategory.getByName("modtest_a"), 1F, 1F);
            // instead of SoundCategory.getByName("modtest_a") you could use Main.MODTEST_A
         }
}
. . .

 

If you add or change  or remove your custom sound categories in your mod, vanilla will gracefully ignore and overwrite the settings. No worries about a crash for a missing custom sound category.

 

If you goof up and add a conflicting sound category you will crash MC. Oops!, but of course as a developer you should know better right!

Section of the client side options.txt where game settings are saved.

 

key_key.hotbar.8:9
key_key.hotbar.9:10
soundCategory_master:1.0
soundCategory_music:0.03521127
soundCategory_record:0.20422535
soundCategory_weather:0.59859157
soundCategory_block:0.42957747
soundCategory_hostile:0.5633803
soundCategory_neutral:0.5140845
soundCategory_player:0.52112675
soundCategory_ambient:0.29577464
soundCategory_voice:0.57042253
soundCategory_mxtune:0.5422535
soundCategory_modtest_a:1.0
soundCategory_modtest_b:1.0
soundCategory_modtest_c:1.0
soundCategory_modtest_d:1.0
soundCategory_modtest_e:1.0
soundCategory_modtest_f:1.0
soundCategory_modtest_g:1.0
soundCategory_modtest_h:1.0
modelPart_cape:true
modelPart_jacket:true

 

 

Here's a demo of it in use:

[embed=425,349]<iframe width="560" height="315" src="https://www.youtube.com/embed/A5lhR-pP4Mg" frameborder="0" allowfullscreen></iframe>[/embed]

 

Here's how the current 1.10.2 vanilla "Music & Sounds Options.." looks after adding several more unique sound categories. Yup, the dialog needs some loving.

 

rH79s.png

 

 

rH7au.png

 

 

rH79s.png

 

Link to comment
Share on other sites

  • 1 month later...

This is a very good feature. I would definitely use it if I update my Mod to 1.11 and it's there. (I would use it in 1.7.10 too, but I don't think the forge team is willing to add stuff to 1.7 :'().

 

One thing that I think needs to get added is a submenu. So you have a button "Mod Sound Sliders" which opens a submenu with a list of all modded sound sliders. (Similar to keybindings). Every mod is a major category, and maybe allow mods to add a minor category within the mod.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.