Jump to content

Recommended Posts

Posted

Figured it out. It is a lot simpler than it looks. Thanks for the help and the links!

 

EDIT: I would I distribute my sounds? The sounds should be placed in the resource file but how I can include the sounds in my ZIP and having them work? Also, I am not sure how would I get an entity to keep playing this ambient sound while it is alive. I saw there is this thing called sound streaming and I am not sure how to use it. I tried calling play sound every tick but it just made REALLY LOUD overlapping sound fxs.

Posted

I already read that link. That's for the help. From what I see, they seem to have their sound files in a "sound" directory in the zip. I will try using that.

 

And another question: How can I make a block to constantly play an ambient sound (when specified to do so by it's tile entity of course)? Industrialcraft has these machines that will keep playing noise as long as they're working. I can not use the world.playSoundEffect function since it doesn't really work well for this. I have a loop able sound track for some of my machines that I would like to have them used.

Posted

I ran into a problem. Let's say my block/entity gets destroyed. The sound will keep playing even when it is gone.

IC2 has that problem as well.

So, what would happen if I did push that shiny red button over there? ... Really? ... Can I try it? ... Damn.

Posted

 

I looked at their code and did the exact same thing but the audio files don't seem to get recognized when I obfuscated it (it works no problem when I place it in the resource folder).

 

        static final String soundPrefix = "/icbm/sound/";
static final String[] soundFiles = {"airstrike", "missilelaunch", "emp", "explosion1", "machinehum", "missileinair", "targetlocked"};

@Override
public void onLoadSoundSettings(SoundManager soundManager)
{
	for(int i = 0; i < soundFiles.length; i++)
	{
		URL url = ICBMSound.class.getClassLoader().getResource(soundPrefix+soundFiles[i]+".ogg");

	    if(url != null)
	    {
			soundManager.getSoundsPool().addSound("icbm.sound."+soundFiles[i], this.getClass().getResource(soundPrefix+soundFiles[i]+".ogg"));
	    }
	    else
	    {
	    	System.out.println("Invalid sound file: " + soundFiles[i]);
	    }
	}
}

 

The directory of my sound files are at /icbm/sound/... inside of my zip. What am I doing wrong?

Posted

So I fiddled around with this a bit and took notes. Maybe it could become a tutorial eventually.

 

Notes about how Forge handles custom sounds:

 

1) The modder overrides getLivingSound() in Entity class to return a string (let’s call it soundString) that represents the sound.

 

2) EntityLiving.playLivingSound() reads getLivingSound() of the Entity and calls World.playSoundAtEntity() with the Entity and soundString as arguments

 

3) World.playSoundAtEntity() passes the soundString to the static method ForgeHooksClient.onPlaySoundAtEntity, and asks for a string back. The string it receives depends on your implementation of ISoundHandler. Most of the time, it will just be soundString (see 5a).

 

4) ForgeHooksClient.onPlaySoundAtEntity checks static variable ForgeHooksClient.soundHandlers2, which is a linked list that contains objects of classes that implement ISoundHandler. If there are no entries in soundHandlers2 the method will return soundString. If there are entries in soundHandlers2 it will go through them and call ISoundHandler.onPlaySoundAtEntity() on each. If any of those handlers return null (even handlers declared by other mods for whatever reason), this method will return null as well. If not, method will return the result of onPlaySoundAtEntity() for the last entry in the list.

 

5a) The unimplemented method, ISoundHandler.onPlaySoundAtEntity() generally should return the namestring it is given--in other words, soundString will usually just propagate up to World.playSoundAtEntity if Forge has loaded no SoundHandlers (because you aren't using custom sounds) or your SoundHandler doesn't do anything fancy.

 

5b) soundHandlers2 is only altered by the method MinecraftForgeClient.registerSoundHandler(), which must be called by the modder. this method will add the given sound handler to soundHandlers2 ONLY if the method onPlaySoundAtEntity() has been declared in the sound handler class.

 

6) registerSoundHandler() also adds any soundHandler it is given to the linked list soundHandlers. When SoundManager invokes loadSoundSettings(), it calls onLoadSoundSettings for all registered soundHandlers.

 

7) The unimplemented ISoundHandler.onLoadSoundSettings() is invoked on all registered soundhandlers when the method SoundManager.loadSoundSettings() is called. The modder should put the sound file import code (as per LexManos’s example) in this method, in a class that implements ISoundHandler or extends SoundHandlerAdaptor, and then register the new SoundHandler.

 

That about right?

Posted

Thats about right. But it doesn't really answer my question (although it makes everything more clear). The problem I am having is that I have to get my players to manually place the sound files in resources/mods/sounds/ directory in order for the sound to be actually found. I can't figure out a way to make the sound play when I store my xxx.ogg files in my mod distribution zip package. Industrialcraft seems to be able to do this with no problem but they are not using the Forge sound handler.

Posted

Yeah, that does seem odd, though I haven't tried it myself. 

 

I do know that Atomicstryker does the same thing with his mods. His workaround isn't actually not that bad although it probably keeps the mod from being loadable via "automatic installers" or whatever.

Posted

btw, is there a reason why you used "Method.class.getClassLoader().getResource()" instead of the way the example did it? I don't know enough Java to know what the difference would be, but I was able to load sounds just fine in my zip file using the example code.

Posted

btw, is there a reason why you used "Method.class.getClassLoader().getResource()" instead of the way the example did it? I don't know enough Java to know what the difference would be, but I was able to load sounds just fine in my zip file using the example code.

 

I used .getClassLoader().getResource() but it didn't seem to work. Does the name of the sound file (e.g "random.explosion") matter?

Posted

Yeah, it does. Actually, the name you give assign it in the sound pool matters too. Check out SoundPool.addSound(). It appears to creates its own reference from the name you give it. It creates this reference as follows:

 

1) cuts off everything after the first "." character.

2) cuts off any digits at the end (this is so all similar sounds will be saved under the same reference)

3) transmutes all "/" to "."

 

So if you give it the string mod/sound/hey.wav the reference it creates will be mod.sound.hey; it'll be that reference which you'll need to access later.

 

Not only that, but it will save the "original" name you gave it as a SoundEntry field, and which will be read in the method SoundManager.playSound(). I think this is so that it can correctly choose a codec for the sound file.

 

This is my code, which works with my files, even in the zip:

 

// Initializes our entries into the Sound Pool
	public void onLoadSoundSettings(SoundManager soundManager) {
		String [] soundFiles = {
				"horse/whinny3.wav",
				"horse/whinny4.wav",
				"horse/snort.wav",
				"horse/snort2.wav",
				"horse/death.wav",
				"horse/hurt.wav"};
		for (int i = 0; i < soundFiles.length; i++){
			soundManager.getSoundsPool().addSound(soundFiles[i], this.getClass().getResource("/MountsMod/sound/" + soundFiles[i]));
		}
	}

 

So to access a random whinny noise, I just reference "horse.whinny".

Posted

Yeah, it does. Actually, the name you give assign it in the sound pool matters too. Check out SoundPool.addSound(). It appears to creates its own reference from the name you give it. It creates this reference as follows:

 

1) cuts off everything after the first "." character.

2) cuts off any digits at the end (this is so all similar sounds will be saved under the same reference)

3) transmutes all "/" to "."

 

So if you give it the string mod/sound/hey.wav the reference it creates will be mod.sound.hey; it'll be that reference which you'll need to access later.

 

Not only that, but it will save the "original" name you gave it as a SoundEntry field, and which will be read in the method SoundManager.playSound(). I think this is so that it can correctly choose a codec for the sound file.

 

This is my code, which works with my files, even in the zip:

 

// Initializes our entries into the Sound Pool
	public void onLoadSoundSettings(SoundManager soundManager) {
		String [] soundFiles = {
				"horse/whinny3.wav",
				"horse/whinny4.wav",
				"horse/snort.wav",
				"horse/snort2.wav",
				"horse/death.wav",
				"horse/hurt.wav"};
		for (int i = 0; i < soundFiles.length; i++){
			soundManager.getSoundsPool().addSound(soundFiles[i], this.getClass().getResource("/MountsMod/sound/" + soundFiles[i]));
		}
	}

 

So to access a random whinny noise, I just reference "horse.whinny".

 

Thanks for the help! I understand about sound a lot more now thanks to your explainations! While I am developing my mod (and I don't have a mod zip file), do I just place all sound files in the jar like how I put all textures in the jar?

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • the modpack keep crashing idk why,cause it never said anything about any mods causing it. crash log:https://drive.google.com/file/d/1iYKlUgvHUob8DjyRc3gqP_Viv_kSHO6L/view?usp=sharing mod list:https://drive.google.com/file/d/1MvMT-z9Jg2BITQ4uLshJ1uOh7q9EMBfC/view?usp=sharing but the server(anternos) works just fine
    • Hello, I am trying to make 2 recipes for a ruby. The first one is turning a block into a ruby and the other one is 9 nuggets into a ruby. But I keep on getting a error java.lang.IllegalStateException: Duplicate recipe rubymod:ruby   Any help would be great on how to fix it
    • Hello everyone, i'm new with programing Mods, and will need a lot of your help if possible,  Im trying to make a new GUI interface responsible to control the Droprate of game, it will control de loot drop and loot table for mobs and even blocks, but i try to make a simple Gui Screen, and wenever i try to use it, the game crash's with the error message in the subject, here is the code im using to:  IDE: IntelliJ Comunity - latest version Forge: 47.3.0 Minecraft version: 1.20.1 mapping_channel: parchment mapping_version=2023.09.03-1.20.1 Crash report link: https://pastebin.com/6dV8k1Fw   Code im using is:    package createchronical.droprateconfig; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import java.util.HashMap; import java.util.Map; public class ConfigScreen extends Screen { private static final ResourceLocation BACKGROUND_TEXTURE = new ResourceLocation("droprateconfig", "textures/gui/config_background.png"); // Mapa de mobs e itens com seus respectivos drop rates private final Map<String, Integer> dropRates = new HashMap<>(); public ConfigScreen() { super(Component.literal("Configurações de Drop Rate")); // Inicializa com valores de drop rate padrão dropRates.put("Zombie", 10); // Exemplo de mob dropRates.put("Creeper", 5); // Exemplo de mob dropRates.put("Iron Ore", 50); // Exemplo de item dropRates.put("Diamond", 2); // Exemplo de item } @Override protected void init() { // Cria um botão para cada mob/item e adiciona na tela int yOffset = this.height / 2 - 100; // Posicionamento inicial for (Map.Entry<String, Integer> entry : dropRates.entrySet()) { String itemName = entry.getKey(); int dropRate = entry.getValue(); // Cria um botão para cada mob/item this.addRenderableWidget(Button.builder( Component.literal(itemName + ": " + dropRate + "%"), button -> onDropRateButtonPressed(itemName) ).bounds(this.width / 2 - 100, yOffset, 200, 20).build()); yOffset += 25; // Incrementa a posição Y para o próximo botão } // Adiciona o botão de "Salvar Configurações" this.addRenderableWidget(Button.builder(Component.literal("Salvar Configurações"), button -> onSavePressed()) .bounds(this.width / 2 - 100, yOffset, 200, 20) .build()); } private void onDropRateButtonPressed(String itemName) { // Lógica para alterar o drop rate do item/mob selecionado // Aqui, vamos apenas incrementar o valor como exemplo int currentRate = dropRates.get(itemName); dropRates.put(itemName, currentRate + 5); // Aumenta o drop rate em 5% } private void onSavePressed() { // Lógica para salvar as configurações (temporariamente apenas na memória) // Vamos apenas imprimir para verificar dropRates.forEach((item, rate) -> { System.out.println("Item: " + item + " | Novo Drop Rate: " + rate + "%"); }); // Fecha a tela após salvar Screen pGuiScreen = null; assert this.minecraft != null; this.minecraft.setScreen(pGuiScreen); } @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { this.renderBackground(guiGraphics); guiGraphics.blit(BACKGROUND_TEXTURE, this.width / 2 - 128, this.height / 2 - 128, 0, 0, 256, 256, 256, 256); super.render(guiGraphics, mouseX, mouseY, partialTicks); } }  
  • Topics

×
×
  • Create New...

Important Information

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