Jump to content

Recommended Posts

Posted

Hello Forge-Community!

 

First of all, I'm an Austrian, so my English isn't the best!

Secondly, I'm a beginner in Java and Forge, please don't judge me too hard! ^^

 

Ok, I wanted to make an dynamic SoundManager which loads the sounds from a custom path respectively custom resource pack which implements IResourcePack!

Everything worked fine, my SoundManager, my ResourcePack and everything else, until I tried to register a sound manager individual for each map.

I tried to give each soundmanager an unique id, here are my classes: (and again, please don't judge me too much for my bad coding skills ^^)

 

My WorldEvents class:

http://pastebin.com/yPEH9QpX

 

My Registry class:

http://pastebin.com/DAzGip3t

 

My WorldRegistry class:

http://pastebin.com/dTRaqURj

 

My SoundManager & SoundFolder class:

http://pastebin.com/Rg1mRXWe

 

And my WorldData class:

http://pastebin.com/iqRyAQxr

 

I coded all myself except the WorldData class for which I needed a tutorial! ^^

Please don't reply with code examples (except there is no alternative)!

Just declare what's wrong if you can help me (like: something in this class must be static or mustn't be final) xD

 

Thank you :P

Posted
  On 9/30/2016 at 5:42 PM, diesieben07 said:

  Quote
Because he would then have to work with zip files
This is not true.

[/qoute]

 

  Quote
And this way, the resources come with the map, so the user don't have to download and set them manually :D
Vanilla Minecraft already supports bundling resource packs with a map.

 

but then it must be a zipped file, and I don't want this ^^

 

EDIT:

And the sounds must be registered anyway!

That's my actual problem, but im open to everything!

(sry if my first post wasn't declaring this obviously)

Posted

Because the user don't need additional programs to edit content, not beacause he hasn't such programms, but it costs more time for the user ^^

second reason, my code will be much bigger with zip methods if I want my mod to change files in that zip!

But if you recommend this way rather than mine, then I really should do that ^^

 

Ok, now with the sound registry

Register the sounds everytime the user added a new sound

Should I do this with a FileWatcher that notifies the mod to register new sounds?

But then the sounds also registered for other maps :/

Posted
  On 9/30/2016 at 6:25 PM, diesieben07 said:

  Quote
Because the user don't need additional programs to edit content, not beacause he hasn't such programms, but it costs more time for the user ^^
While developing the map the user can use the folder resource pack method and only zip up the resource pack when they distribute the map.

 

Must the user do this by itself, or do i have to make this possible with my mod

 

  Quote

  Quote
second reason, my code will be much bigger with zip methods if I want my mod to change files in that zip!
Why do you want to edit the user's resource pack?  :o

 

Haha no, I meant that if the user use the method to change single textures, my mod changes them!

But now I know, that I should do this with resourcepacks too ^^

 

  Quote

  Quote
Register the sounds everytime the user added a new sound

Should I do this with a FileWatcher that notifies the mod to register new sounds?

Make the IResourcePack regenerate the generated sounds.json data using an
IResourceManagerReloadListener

, which will tell you when Minecraft reloads the resources. You can then use the file watch API to tell Minecraft to reload resources automatically if a new file is added.

 

Yeah, but the new sounds aren't registered in the forge registry then ^^

(wow, i really should do something for my english, horrible :o)

Posted
  Quote
You cannot register stuff to registries after preInit. If you must create new SoundEvents, you must restart the game.

Sure, it has worked when I registered them by loading the world ^^

But then they also registered for all worlds, because they registered for the mod and not for single world

And if a world uses a sound with the same name as another, there was a conflict, because soundevents can't registered twice

but I think you already know that haha :D

so i tried to give each world an UUID which the sound also gets

and thats why I let my mod write the sounds JSON, otherwise the user has to write the uuid in front of each sound in the sounds.json :P

Posted
  On 9/30/2016 at 8:06 PM, diesieben07 said:

Doing this will cause all kinds of problems because of dynamic ID remapping (IDs change between worlds). If you just add stuff later, the registries might break.

 

Where would these newly created sound events be played from anyways?

 

Ok, didn't know that!

NPCs for example.

The user can set the sound via a GUI.

Or for background music, like in adventure games triggered by a block ^^

 

Maybe I should create a new instance of the existing soundsystem and edit some base classes to mute the old one?

But I think that's not a good idea, mod compatibility is a big problem then!

Although it doesn't matter if my mod is compatible or not, because it should be a single mod anyway.

Ah, maybe I should say that this mod should be a SinglePlayer mod!

I think that's very important information ^^

Posted

I know that's not supported, but it's possible!

I've done it many times!

 

  On 9/30/2016 at 9:11 PM, diesieben07 said:

Unfortunately I am not currently at my IDE so I am not 100% sure how you might want to solve this. One idea would be to bypass the SoundEvent registry, but I am not sure how feasible that is.

Maybe i could create an class implementing the IWorldEventListener and create my own

 

public void playSound(@Nullable EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch)
    {
        net.minecraftforge.event.entity.PlaySoundAtEntityEvent event = net.minecraftforge.event.ForgeEventFactory.onPlaySoundAtEntity(player, soundIn, category, volume, pitch);
        if (event.isCanceled() || event.getSound() == null) return;
        soundIn = event.getSound();
        category = event.getCategory();
        volume = event.getVolume();
        pitch = event.getPitch();

        for (int i = 0; i < this.eventListeners.size(); ++i)
        {
            ((IWorldEventListener)this.eventListeners.get(i)).playSoundToAllNearExcept(player, soundIn, category, x, y, z, volume, pitch);
        }
    }

method.

 

I know that this isn't easy, because there are so many other classes needed to play the sound,

but if i could create my own SoundPlayEvent and register the soundevents in an additional map (temporary data, until i unloaded a map and register new soundevents after loading another map)

in my mod, would that work then?

I create a new superclass for my entities that handle the new sound management and let my existing entity inherit from that class!

Maybe this should work ^^

 

EDIT:

I could read thorugh the classes to learn how the sound system is working and then create my OWN CUSTOM sound system, especially for this mod ^^

Posted

After many hours of struggling, i've found this useful method:

 

public void playSound(ISound p_sound)
    {
        if (this.loaded)
        {
            p_sound = net.minecraftforge.client.ForgeHooksClient.playSound(this, p_sound);
            if (p_sound == null) return;

            SoundEventAccessor soundeventaccessor = p_sound.createAccessor(this.sndHandler);
            ResourceLocation resourcelocation = p_sound.getSoundLocation();

            if (soundeventaccessor == null)
            {
                if (UNABLE_TO_PLAY.add(resourcelocation))
                {
                    LOGGER.warn(LOG_MARKER, "Unable to play unknown soundEvent: {}", new Object[] {resourcelocation});
                }
            }
            else
            {
                if (!this.listeners.isEmpty())
                {
                    for (ISoundEventListener isoundeventlistener : this.listeners)
                    {
                        isoundeventlistener.soundPlay(p_sound, soundeventaccessor);
                    }
                }

                if (this.sndSystem.getMasterVolume() <= 0.0F)
                {
                    LOGGER.debug(LOG_MARKER, "Skipped playing soundEvent: {}, master volume was zero", new Object[] {resourcelocation});
                }
                else
                {
                    Sound sound = p_sound.getSound();

                    if (sound == SoundHandler.MISSING_SOUND)
                    {
                        if (UNABLE_TO_PLAY.add(resourcelocation))
                        {
                            LOGGER.warn(LOG_MARKER, "Unable to play empty soundEvent: {}", new Object[] {resourcelocation});
                        }
                    }
                    else
                    {
                        float f3 = p_sound.getVolume();
                        float f = 16.0F;

                        if (f3 > 1.0F)
                        {
                            f *= f3;
                        }

                        SoundCategory soundcategory = p_sound.getCategory();
                        float f1 = this.getClampedVolume(p_sound);
                        float f2 = this.getClampedPitch(p_sound);

                        if (f1 == 0.0F)
                        {
                            LOGGER.debug(LOG_MARKER, "Skipped playing sound {}, volume was zero.", new Object[] {sound.getSoundLocation()});
                        }
                        else
                        {
                            boolean flag = p_sound.canRepeat() && p_sound.getRepeatDelay() == 0;
                            String s = MathHelper.getRandomUuid(ThreadLocalRandom.current()).toString();
                            ResourceLocation resourcelocation1 = sound.getSoundAsOggLocation();

                            if (sound.isStreaming())
                            {
                                this.sndSystem.newStreamingSource(false, s, getURLForSoundResource(resourcelocation1), resourcelocation1.toString(), flag, p_sound.getXPosF(), p_sound.getYPosF(), p_sound.getZPosF(), p_sound.getAttenuationType().getTypeInt(), f);
                                net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.sound.PlayStreamingSourceEvent(this, p_sound, s));
                            }
                            else
                            {
                                this.sndSystem.newSource(false, s, getURLForSoundResource(resourcelocation1), resourcelocation1.toString(), flag, p_sound.getXPosF(), p_sound.getYPosF(), p_sound.getZPosF(), p_sound.getAttenuationType().getTypeInt(), f);
                                net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.sound.PlaySoundSourceEvent(this, p_sound, s));
                            }

                            LOGGER.debug(LOG_MARKER, "Playing sound {} for event {} as channel {}", new Object[] {sound.getSoundLocation(), resourcelocation1, s});
                            this.sndSystem.setPitch(s, f2);
                            this.sndSystem.setVolume(s, f1);
                            this.sndSystem.play(s);
                            this.playingSoundsStopTime.put(s, Integer.valueOf(this.playTime + 20));
                            this.playingSounds.put(s, p_sound);

                            if (soundcategory != SoundCategory.MASTER)
                            {
                                this.categorySounds.put(soundcategory, s);
                            }

                            if (p_sound instanceof ITickableSound)
                            {
                                this.tickableSounds.add((ITickableSound)p_sound);
                            }
                        }
                    }
                }
            }
        }
    }

 

Could this work?:

1. Create custom SoundManager and inherit from the existing one

2. Get the most important fields via Java Reflection (because they're all private)

3. Override the playsound method

 

Maybe this should do it! ^^

Posted

I see opportunity here:

 

            p_sound = net.minecraftforge.client.ForgeHooksClient.playSound(this, p_sound);
            if (p_sound == null) return;

 

That thar is a Forge hook. You can write an event handler to do almost anything with that incoming p-sound, and then return null so that the vanilla method quits without doing anything else.

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Posted

Yeah, I wanted to do so but I thought that would be way too insecure!

What if my sound overlaps another playing sounds and causes some problems?

I could use the SoundSystem in the SoundManager, but is this safe enough?

 

this.sndSystem.newStreamingSource(false, s, getURLForSoundResource(resourcelocation1), resourcelocation1.toString(), flag, p_sound.getXPosF(), p_sound.getYPosF(), p_sound.getZPosF(), p_sound.getAttenuationType().getTypeInt(), f);

 

For example!

 

When i was digging deeper, I found this one:

class SoundSystemStarterThread extends SoundSystem
    {
        private SoundSystemStarterThread()
        {
        }

        public boolean playing(String p_playing_1_)
        {
            synchronized (SoundSystemConfig.THREAD_SYNC)
            {
                if (this.soundLibrary == null)
                {
                    return false;
                }
                else
                {
                    Source source = (Source)this.soundLibrary.getSources().get(p_playing_1_);
                    return source == null ? false : source.playing() || source.paused() || source.preLoad;
                }
            }
        }
    }

 

But Threads are not my friends!

I know almost nothing about threads.

Doesn't matter how often I've read something about them!

Posted

How did I know that there will be a thread exception?

 

http://pastebin.com/pb8U8i2m

 

First time playing the sound worked just fine, but then:

 

[05:44:04] [Thread-14/ERROR]: Error in class 'CodecJOrbis'
[05:44:04] [Thread-14/ERROR]: Unable to acquire inputstream in method 'initialize'.
[05:44:04] [Thread-14/WARN]: ERROR MESSAGE:
[05:44:04] [Thread-14/INFO]: C:\Users\Rexozz\Desktop\forge 1.10 modding\PixelEngine\saves\Neue Welt\mapres\sounds\sound\block.grass.step.ogg (Das System kann die angegebene Datei nicht finden)
[05:44:04] [Thread-14/WARN]: STACK TRACE:
[05:44:04] [Thread-14/INFO]: java.io.FileInputStream.open0(Native Method)
[05:44:04] [Thread-14/INFO]: java.io.FileInputStream.open(Unknown Source)
[05:44:04] [Thread-14/INFO]: java.io.FileInputStream.<init>(Unknown Source)
[05:44:04] [Thread-14/INFO]: java.io.FileInputStream.<init>(Unknown Source)
[05:44:04] [Thread-14/INFO]: sun.net.www.protocol.file.FileURLConnection.connect(Unknown Source)
[05:44:04] [Thread-14/INFO]: sun.net.www.protocol.file.FileURLConnection.getInputStream(Unknown Source)
[05:44:04] [Thread-14/INFO]: paulscode.sound.codecs.CodecJOrbis.initialize(CodecJOrbis.java:281)
[05:44:04] [Thread-14/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.loadSound(LibraryLWJGLOpenAL.java:392)
[05:44:04] [Thread-14/INFO]: paulscode.sound.libraries.LibraryLWJGLOpenAL.newSource(LibraryLWJGLOpenAL.java:640)
[05:44:04] [Thread-14/INFO]: paulscode.sound.SoundSystem.CommandNewSource(SoundSystem.java:1800)
[05:44:04] [Thread-14/INFO]: paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2415)
[05:44:04] [Thread-14/INFO]: paulscode.sound.CommandThread.run(CommandThread.java:121)

 

This is where the sound plays:

http://pastebin.com/gUsSSujt

Posted

Haha, it works now, I just wonder how long!

Are there any improvements that I could do?

 

PacketClass:

http://pastebin.com/KvCqVDM7

 

PlaySound in PEEntityCreature:

public class PEEntityCreature extends EntityCreature implements INpc{
public PEEntityCreature(World worldIn) {
	super(worldIn);
}

@Override
public void playSound(SoundEvent sound, float volume, float pitch) {
        if (!this.isSilent()){
        	if(sound.getSoundName().equals(this.getDeathSound().getSoundName())||sound.getSoundName().equals(this.getHurtSound().getSoundName()))
            	PacketHandler.sendToAllAround(new C00PacketSendSound(new ImplSound(sound,this.getSoundCategory(),volume,pitch,this.posX,this.posY,this.posZ)), this.dimension, this.posX, this.posY, this.posZ, volume > 1.0F ? (double)(16.0F * volume) : 16.0D);
        	else
        		super.playSound(sound, volume, pitch);
        }
    }
}

Guest
This topic is now closed to further replies.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hi everyone, I'm currently developing a Forge 1.21 mod for Minecraft and I want to display a custom HUD overlay for a minigame. My goal: When the game starts, all players should see an item/block icon (from the base game, not a custom texture) plus its name/text in the HUD – similar to how the bossbar overlay works. The HUD should appear centered above the hotbar (or at a similar prominent spot), and update dynamically (icon and name change as the target item changes). What I've tried: I looked at many online tutorials and several GitHub repos (e.g. SeasonHUD, MiniHUD), but most of them use NeoForge or Forge versions <1.20 that provide the IGuiOverlay API (e.g. implements IGuiOverlay, RegisterGuiOverlaysEvent). In Forge 1.21, it seems that neither IGuiOverlay nor RegisterGuiOverlaysEvent exist anymore – at least, I can't import them and they are missing from the docs and code completion. I tried using RenderLevelStageEvent as a workaround but it is probably not intended for custom HUDs. I am not using NeoForge, and switching the project to NeoForge is currently not an option for me. I tried to look at the original minecraft source code to see how elements like hearts, hotbar etc are drawn on the screen but I am too new to Minecraft modding to understand. What I'm looking for: What is the correct way to add a custom HUD element (icon + text) in Forge 1.21, given that the previous overlay API is missing? Is there a new recommended event, callback, or method in Forge 1.21 for custom HUD overlays, or is everyone just using a workaround? Is there a minimal open-source example repo for Forge 1.21 that demonstrates a working HUD overlay without relying on NeoForge or deprecated Forge APIs? My ideal solution: Centered HUD element with an in-game item/block icon (from the base game's assets, e.g. a diamond or any ItemStack / Item) and its name as text, with a transparent background rectangle. It should be visible to the players when the mini game is running. Easy to update the item (e.g. static variable or other method), so it can change dynamically during the game. Any help, code snippets, or up-to-date references would be really appreciated! If this is simply not possible right now in Forge 1.21, it would also help to know that for sure. Thank you very much in advance!
    • The simple answer is there is not an easy way. You would need to know how to program in Java, as well as at least some familiarity with how Forge works so you could port the differences. You would also need the sourcecode for the original mod, and permission from the author to modify it, if they did not use some sort of open source license. So it's not impossible, but it would take some effort, but doing so would open up a whole new world of possibilities for you!
    • Does it still crash if you remove holdmyitems? Looks like that mod doesn't work on a server as far as I can tell from the error.  
    • Crashes the server when trying to start. Error code -1. Log  
  • Topics

×
×
  • Create New...

Important Information

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