Topic category: Advanced modding
I've been experimenting with minecraft's music system a bit and I kinda understand how it works. Before we continue, I should mention that this is NOT a Tutorial on how to add custom music in your dimension! The reason why I made this topic is because I want to get some teaming-up thing going on and I want us to try solving this issue together and maybe we could finally be able to get our dimensions some cool custom music. If anyone also experimented with this, please, share your information in this topic. Now, if everything I tell is wrong, then uhh yeah oof... call me an idiot. Anyway, let me share my research on minecraft's music system:
In order to add Custom Music for your dimension you need:
-
At Least 1 registered sound file (obviously)
- A New Music Type
And...
- A piece of code that has to be put in the main .java file of your mod ( <MODID aka your mod's name>.java )
If there's any other requirements you know, then I'm telling again: please, share your information.
I suppose we can skip the first step, so onto the next step.
So, inorder to make the game recognize your sound as music, you have to add a new Music Type. It will not work, if you just import your soundtrack and categorize it as "music". That'll just set the Volume of the sound to the Value of the Music Volume. To create a new Music Type, you have to put this code in. Remember to always import the neccessary packages:
public static MusicTicker.MusicType addMusicType(String name, SoundEvent sound, int minDelay, int maxDelay)
{
return addEnum(MusicTicker.MusicType.class, name, sound, minDelay, maxDelay);
}
The code seems self explanatory, so I don't need to explain it.
Now, I don't know where this piece of code needs to be placed in. If it can be anywhere or if it has to be in a specific spot.
Now comes the code that's supposed to make the magic happen. This one has to be put in your mod's main file.
First, I'm going to show you how the code looks like in Minecraft and I will explain how I think this works, then I will show you how I assume the code should look like in your mod file.
Here's the code extracted from Minecraft. Take a look:
public MusicTicker.MusicType getAmbientMusicType()
{
if (this.currentScreen instanceof GuiWinGame)
{
return MusicTicker.MusicType.CREDITS;
}
else if (this.player != null)
{
MusicTicker.MusicType type = this.world.provider.getMusicType();
if (type != null) return type;
if (this.player.world.provider instanceof WorldProviderHell)
{
return MusicTicker.MusicType.NETHER;
}
else if (this.player.world.provider instanceof WorldProviderEnd)
{
return this.ingameGUI.getBossOverlay().shouldPlayEndBossMusic() ? MusicTicker.MusicType.END_BOSS : MusicTicker.MusicType.END;
}
else
{
return this.player.capabilities.isCreativeMode && this.player.capabilities.allowFlying ? MusicTicker.MusicType.CREATIVE : MusicTicker.MusicType.GAME;
}
}
else
{
return MusicTicker.MusicType.MENU;
}
}
Did you take a look? Great! Now, let me explain you how it works, if you don't understand it's code:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (this.currentScreen instanceof GuiWinGame)
{
return MusicTicker.MusicType.CREDITS;
}
*This determines if the player should get the Music Type CREDITS when the Credits are rolling. Seems obvious.*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if (this.player != null) {...}
*If the credits are not rolling, this line will check, if the player is playing. If so, the game will run the code that is stored in the two brackets.*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CONTENTS INSIDE THE BRACKETS:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MusicTicker.MusicType type = this.world.provider.getMusicType();
if (type != null) return type;
*The upper line of this code will read Music Types which will be given by World Providers (aka Dimensions)
below this code. The line below checks, If the World Providers give valid Music Types, it'll return the type, meaning it will keep the information and not throw it away. For example, our custom dimensions have no
valid Music Types. When there's no code for them to give Music Types, they give the value "null" which means here "change to default".*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (this.player.world.provider instanceof WorldProviderHell)
{
return MusicTicker.MusicType.NETHER;
}
*This line checks, if the player is in a world provider which is an instance of "WorldProviderHell" (The Nether).
If so, the game recieves the Music Type NETHER which will then play the Nether background music.*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if (this.player.world.provider instanceof WorldProviderEnd)
{
return this.ingameGUI.getBossOverlay().shouldPlayEndBossMusic() ? MusicTicker.MusicType.END_BOSS : MusicTicker.MusicType.END;
}
*If the player is not in the nether and instead in The End, the game will first check if the player sees a boss health bar. After that is checked, the the game then checks if the End boss soundtrack should be played. I assume that checks, if the boss is the enderdragon. If these conditions are true, the End Boss soundtrack will be played. If not, it'll play the normal End Dimension Music.*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else
{
return this.player.capabilities.isCreativeMode && this.player.capabilities.allowFlying ? MusicTicker.MusicType.CREATIVE : MusicTicker.MusicType.GAME;
}
*If anything above is not true, the game will run this line of code. First, the game checks, if the player is in creative mode, after that it checks, if the player is flying or allowed to fly. If these conditions are true the game recieves the Music Type CREATIVE, if it's not true it will get back to default.*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CONTENTS OUTSIDE THE BRACKETS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else
{
return MusicTicker.MusicType.MENU;
}
}
*This last piece of code will be run, if everything above this code is not true. So, if the player isn't even playing, the game gets
the Music Type MENU.*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now since you now understand the code here's how I assume should the code look like in your mod file:
public MusicTicker.MusicType getAmbientMusicType()
{
if (this.player != null)
{
MusicTicker.MusicType type = this.world.provider.getMusicType();
if (type != null) return type;
if (this.player.world.provider instanceof <YourWorldProvider>)
{
return MusicTicker.MusicType.<YourMusicType>;
}
}
}
Even through this seems complete, it isn't. I have found a few issues I cannot solve and there's one we can't solve. Let me list these ones up:
- Where do you put in the Code that adds your custom Music Type
- Variable "player" and "world" are unkown to the console, eventhough every package is imported. Errors appear.
.java:494: error: cannot find symbol
if (this.player != null)
^
symbol: variable player
.java:496: error: cannot find symbol
MusicTicker.MusicType type = this.world.provider.getMusicType();
^
symbol: variable world
.java:499: error: cannot find symbol
if (this.player.world.provider instanceof <TheWorldProvider>)
^
symbol: variable player
3 errors
.java:494: error: cannot find symbol
if (this.player != null)
^
symbol: variable player
.java:496: error: cannot find symbol
MusicTicker.MusicType type = this.world.provider.getMusicType();
^
symbol: variable world
.java:499: error: cannot find symbol
if (this.player.world.provider instanceof <TheWorldProvider>)
^
symbol: variable player
3 errors
And the largest issue of all is that MCreator overrides your Mod's Main file everytime you build or play your mod which makes this impossible to make.
Now, I'm not a java coding expert, but I think we're close to finding out how brackground music works in Minecraft! The only real obstacle is MCreator overriding the main file. Feel free to give some feedback on this topic, if you like to! I hope I didn't forget anything...
EDIT: Oof I forgot something. Incase if you want to look into the code yourself, here are files you need to search for:
EnumHelperClient : located in net/minecraftforge/client
Minecraft : located in net/minecraft/client
This will be fixed in MCreator 1.9.1 :) Check the changelog for more info.
Oh, neat! :D