diff --git a/forge/forge_client/src/net/minecraft/src/forge/ForgeHooksClient.java b/forge/forge_client/src/net/minecraft/src/forge/ForgeHooksClient.java index 0b653a1e8..b3ada4596 100644 --- a/forge/forge_client/src/net/minecraft/src/forge/ForgeHooksClient.java +++ b/forge/forge_client/src/net/minecraft/src/forge/ForgeHooksClient.java @@ -10,6 +10,7 @@ import net.minecraft.src.Entity; import net.minecraft.src.ModLoader; import net.minecraft.src.Packet100OpenWindow; import net.minecraft.src.RenderBlocks; +import net.minecraft.src.SoundPoolEntry; import net.minecraft.src.Tessellator; import net.minecraft.src.RenderGlobal; import net.minecraft.src.EntityPlayer; @@ -392,4 +393,73 @@ public class ForgeHooksClient e.printStackTrace(); } } + + public static LinkedList soundHandlers = new LinkedList(); + public static void onSetupAudio(SoundManager soundManager) + { + for (ISoundHandler handler : soundHandlers) + { + handler.onSetupAudio(soundManager); + } + } + + public static void onLoadSoundSettings(SoundManager soundManager) + { + for (ISoundHandler handler : soundHandlers) + { + handler.onLoadSoundSettings(soundManager); + } + } + + public static SoundPoolEntry onPlayBackgroundMusic(SoundManager soundManager, SoundPoolEntry entry) + { + for (ISoundHandler handler : soundHandlers) + { + entry = handler.onPlayBackgroundMusic(soundManager, entry); + if (entry == null) + { + return null; + } + } + return entry; + } + + public static SoundPoolEntry onPlayStreaming(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z) + { + for (ISoundHandler handler : soundHandlers) + { + entry = handler.onPlayStreaming(soundManager, entry, soundName, x, y, z); + if (entry == null) + { + return null; + } + } + return entry; + } + + public static SoundPoolEntry onPlaySound(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z, float volume, float pitch) + { + for (ISoundHandler handler : soundHandlers) + { + entry = handler.onPlaySound(soundManager, entry, soundName, x, y, z, volume, pitch); + if (entry == null) + { + return null; + } + } + return entry; + } + + public static SoundPoolEntry onPlaySoundEffect(SoundManager soundManager, SoundPoolEntry entry, String soundName, float volume, float pitch) + { + for (ISoundHandler handler : soundHandlers) + { + entry = handler.onPlaySoundEffect(soundManager, entry, soundName,volume, pitch); + if (entry == null) + { + return null; + } + } + return entry; + } } diff --git a/forge/forge_client/src/net/minecraft/src/forge/ISoundHandler.java b/forge/forge_client/src/net/minecraft/src/forge/ISoundHandler.java new file mode 100644 index 000000000..727345914 --- /dev/null +++ b/forge/forge_client/src/net/minecraft/src/forge/ISoundHandler.java @@ -0,0 +1,95 @@ +package net.minecraft.src.forge; + +import net.minecraft.src.SoundManager; +import net.minecraft.src.SoundPoolEntry; + +public interface ISoundHandler +{ + /** + * This event is raised by the SoundManager when it does its first setup of the + * SoundSystemConfig's codecs, use this function to add your own codecs. + * @param soundManager The SoundManager instance + */ + void onSetupAudio(SoundManager soundManager); + + /** + * Raised by the SoundManager.loadSoundSettings, this would be a good place for + * adding your custom sounds to the SoundPool. + * + * @param soundManager The SoundManager instance + */ + void onLoadSoundSettings(SoundManager soundManager); + + /** + * Raised when the SoundManager tries to play a Background Music file, + * If you return null from this function it will prevent the sound from being played, + * you can return a different entry if you want to change the sound being played. + * + * If you do not want to change anything, just return the passed in entry. + * + * @param soundManager The SoundManager instance + * @param entry The current entry that will be played + * @return The new sound entry to play, or the current one passed in. + */ + SoundPoolEntry onPlayBackgroundMusic(SoundManager soundManager, SoundPoolEntry entry); + + /** + * Raised when the SoundManager tries to play a 'Streaming' file, + * in vanilla it is only the Jukebox that uses this function. + * + * If you return null from this function it will prevent the sound from being played, + * you can return a different entry if you want to change the sound being played. + * + * If you do not want to change anything, just return the passed in entry. + * + * @param soundManager The SoundManager instance + * @param entry The current entry that will be played + * @param soundName The name of the request sound + * @param x The X position where the sound will be played + * @param y The Y position where the sound will be played + * @param z The Z position where the sound will be played + * @return The new sound entry to play, or the current one passed in. + */ + SoundPoolEntry onPlayStreaming(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z); + + /*** + * Raised when the SoundManager tries to play a normal sound, + * dogs barking, footsteps, etc. THe majority of all sounds during normal game play. + * + * If you return null from this function it will prevent the sound from being played, + * you can return a different entry if you want to change the sound being played. + * + * If you do not want to change anything, just return the passed in entry. + * + * @param soundManager The SoundManager instance + * @param entry The current entry that will be played + * @param soundName The name of the request sound + * @param x The X position where the sound will be played + * @param y The Y position where the sound will be played + * @param z The Z position where the sound will be played + * @param volume The sound's volume, between 0.0 and 1.0 + * @param pitch The sound's pitch + * @return The new sound entry to play, or the current one passed in. + */ + SoundPoolEntry onPlaySound(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z, float volume, float pitch); + + /** + * Raised when the SoundManager tries to play a effect sound, + * currently the only known sounds are 'random.click' when a GUI button is clicked, + * or 'portal.trigger' and 'portal.travel' when the player is near/inside a portal. + * + * If you return null from this function it will prevent the sound from being played, + * you can return a different entry if you want to change the sound being played. + * + * If you do not want to change anything, just return the passed in entry. + * + * @param soundManager The SoundManager instance + * @param entry The current entry that will be played + * @param soundName The name of the request sound + * @param volume The sound's volume, between 0.0 and 1.0 + * @param pitch The sound's pitch + * @return The new sound entry to play, or the current one passed in. + */ + SoundPoolEntry onPlaySoundEffect(SoundManager soundManager, SoundPoolEntry entry, String soundName, float volume, float pitch); + +} diff --git a/forge/forge_client/src/net/minecraft/src/forge/MinecraftForgeClient.java b/forge/forge_client/src/net/minecraft/src/forge/MinecraftForgeClient.java index e47d99650..4594e0032 100755 --- a/forge/forge_client/src/net/minecraft/src/forge/MinecraftForgeClient.java +++ b/forge/forge_client/src/net/minecraft/src/forge/MinecraftForgeClient.java @@ -55,6 +55,15 @@ public class MinecraftForgeClient { ForgeHooksClient.renderWorldLastHandlers.add(handler); } + + /** + * Registers a Sound Handler + * @param handler The handler + */ + public static void registerSoundHandler(ISoundHandler handler) + { + ForgeHooksClient.soundHandlers.add(handler); + } /** Bind a texture. This is used to bind a texture file when * performing your own rendering, rather than using ITextureProvider. diff --git a/forge/forge_client/src/net/minecraft/src/forge/ModCompatibilityClient.java b/forge/forge_client/src/net/minecraft/src/forge/ModCompatibilityClient.java new file mode 100644 index 000000000..1fb70705c --- /dev/null +++ b/forge/forge_client/src/net/minecraft/src/forge/ModCompatibilityClient.java @@ -0,0 +1,177 @@ +package net.minecraft.src.forge; + +import java.io.File; +import java.io.IOException; + +import paulscode.sound.SoundSystemConfig; + +import net.minecraft.client.Minecraft; +import net.minecraft.src.*; + +public class ModCompatibilityClient +{ + /** + * Trys to get the class for the specified name, will also try the + * net.minecraft.src package in case we are in MCP + * Returns null if not found. + * + * @param name The class name + * @return The Class, or null if not found + */ + private static Class getClass(String name) + { + try + { + return Class.forName(name); + } + catch (Exception e) + { + try + { + return Class.forName("net.minecraft.src." + name); + } + catch (Exception e2) + { + return null; + } + } + } + + /************************************************************************************************ + * Risugami's AudioMod Compatibility + * http://www.minecraftforum.net/topic/75440- + * + * AudioMod adds a few extra codecs, loads audio from /resources/mods/*, + * introduces the concept of 'cave' sounds, which are determined by if + * the player is underneath a solid block. + * + * It also lowers the interval between background music songs to 6000 + */ + public static SoundPool audioModSoundPoolCave; + private static int isAudioModInstalled = -1; + + /** + * Determine if AudioMod is installed by checking for the existence of IBMX Codec, + * I wish there was a less ambiguous way, but there isn't. + * @return True if the IBMX codec was found (indicating AudioMod is installed) + */ + public static boolean isAudioModInstalled() + { + if (isAudioModInstalled == -1) + { + isAudioModInstalled = (getClass("paulscode.sound.codecs.CodecIBXM") != null ? 1 : 0); + } + return isAudioModInstalled == 1; + } + + /** + * Populates the sound pools with with sounds from the /resources/mods folder + * And sets the interval between background music to 6000 + * + * @param mngr The SoundManager instance + */ + public static void audioModLoad(SoundManager mngr) + { + if (!isAudioModInstalled()) + { + return; + } + audioModSoundPoolCave = new SoundPool(); + audioModLoadModAudio("minecraft/resources/mod/sound", mngr.getSoundsPool()); + audioModLoadModAudio("minecraft/resources/mod/streaming", mngr.getStreamingPool()); + audioModLoadModAudio("minecraft/resources/mod/music", mngr.getMusicPool()); + audioModLoadModAudio("minecraft/resources/mod/cavemusic", audioModSoundPoolCave); + + if (mngr.MUSIC_INTERVAL == 12000) + { + mngr.MUSIC_INTERVAL = 6000; + } + } + + /** + * Walks the given path in the Minecraft app directory and adds audio to the SoundPool + * @param path The path to walk + * @param pool The pool to add sound to + */ + private static void audioModLoadModAudio(String path, SoundPool pool) + { + File folder = Minecraft.getAppDir(path); + + try + { + audioModWalkFolder(folder, folder, pool); + } + catch (IOException ex) + { + ModLoader.getLogger().fine("Loading Mod audio failed for folder: " + path); + ModLoader.getLogger().fine(ex.toString()); + ex.printStackTrace(); + } + } + + /** + * Walks the folder path recursively and calls pool.addSound on any file it finds. + * + * @param base The base path for the folder, determines the name when calling addSound + * @param folder The current folder + * @param pool The SoundPool to add the sound to + * @throws IOException + */ + private static void audioModWalkFolder(File base, File folder, SoundPool pool) throws IOException + { + if (folder.exists() || folder.mkdirs()) + { + for (File file : folder.listFiles()) + { + if (!file.getName().startsWith(".")) + { + if (file.isDirectory()) + { + audioModWalkFolder(base, file, pool); + } + else if (file.isFile()) + { + String subpath = file.getPath().substring(base.getPath().length() + 1).replace('\\', '/'); + pool.addSound(subpath, file); + } + } + } + } + } + + /** + * Adds the IBXM codec and associates it with .xm, .s3m, and .mod + */ + public static void audioModAddCodecs() + { + Class codec = getClass("paulscode.sound.codecs.CodecIBXM"); + if (isAudioModInstalled() && codec != null) + { + SoundSystemConfig.setCodec("xm", codec); + SoundSystemConfig.setCodec("s3m", codec); + SoundSystemConfig.setCodec("mod", codec); + } + } + + /** + * If the current player is underground, it picks a random song from the cave sound pool, + * if they are not it returns the passed in entry. + * + * @param soundManager The SoundManager instance + * @param current The currently selected entry + * @return A soundPool entry to be played as the background music + */ + public static SoundPoolEntry audioModPickBackgroundMusic(SoundManager soundManager, SoundPoolEntry current) + { + Minecraft mc = ModLoader.getMinecraftInstance(); + if (isAudioModInstalled() && mc != null && mc.theWorld != null && audioModSoundPoolCave != null) + { + Entity ent = mc.renderViewEntity; + int x = MathHelper.func_40346_b(ent.posX); + int y = MathHelper.func_40346_b(ent.posY); + int z = MathHelper.func_40346_b(ent.posZ); + return (mc.theWorld.canBlockSeeTheSky(x, y, z) ? current : audioModSoundPoolCave.getRandomSound()); + } + return current; + } +} diff --git a/forge/patches/minecraft/net/minecraft/src/SoundManager.java.patch b/forge/patches/minecraft/net/minecraft/src/SoundManager.java.patch new file mode 100644 index 000000000..1d2071033 --- /dev/null +++ b/forge/patches/minecraft/net/minecraft/src/SoundManager.java.patch @@ -0,0 +1,108 @@ +--- ../src_base/minecraft/net/minecraft/src/SoundManager.java 0000-00-00 00:00:00.000000000 -0000 ++++ ../src_work/minecraft/net/minecraft/src/SoundManager.java 0000-00-00 00:00:00.000000000 -0000 +@@ -2,6 +2,9 @@ + + import java.io.File; + import java.util.Random; ++ ++import net.minecraft.src.forge.ForgeHooksClient; ++import net.minecraft.src.forge.ModCompatibilityClient; + import paulscode.sound.SoundSystem; + import paulscode.sound.SoundSystemConfig; + import paulscode.sound.codecs.CodecJOrbis; +@@ -36,10 +39,12 @@ + /** RNG. */ + private Random rand = new Random(); + private int ticksBeforeMusic; ++ ++ public static int MUSIC_INTERVAL = 12000; + + public SoundManager() + { +- this.ticksBeforeMusic = this.rand.nextInt(12000); ++ this.ticksBeforeMusic = this.rand.nextInt(MUSIC_INTERVAL); + } + + /** +@@ -54,6 +59,8 @@ + { + this.tryToSetLibraryAndCodecs(); + } ++ ModCompatibilityClient.audioModLoad(this); ++ ForgeHooksClient.onLoadSoundSettings(this); + } + + /** +@@ -73,6 +80,8 @@ + SoundSystemConfig.setCodec("ogg", CodecJOrbis.class); + SoundSystemConfig.setCodec("mus", CodecMus.class); + SoundSystemConfig.setCodec("wav", CodecWav.class); ++ ModCompatibilityClient.audioModAddCodecs(); ++ ForgeHooksClient.onSetupAudio(this); + sndSystem = new SoundSystem(); + this.options.soundVolume = var1; + this.options.musicVolume = var2; +@@ -161,10 +170,12 @@ + } + + SoundPoolEntry var1 = this.soundPoolMusic.getRandomSound(); ++ var1 = ModCompatibilityClient.audioModPickBackgroundMusic(this, var1); ++ var1 = ForgeHooksClient.onPlayBackgroundMusic(this, var1); + + if (var1 != null) + { +- this.ticksBeforeMusic = this.rand.nextInt(12000) + 12000; ++ this.ticksBeforeMusic = this.rand.nextInt(MUSIC_INTERVAL) + MUSIC_INTERVAL; + sndSystem.backgroundMusic("BgMusic", var1.soundUrl, var1.soundName, false); + sndSystem.setVolume("BgMusic", this.options.musicVolume); + sndSystem.play("BgMusic"); +@@ -214,6 +225,7 @@ + if (par1Str != null) + { + SoundPoolEntry var8 = this.soundPoolStreaming.getRandomSoundFromSoundPool(par1Str); ++ var8 = ForgeHooksClient.onPlayStreaming(this, var8, par1Str, par2, par3, par4); + + if (var8 != null && par5 > 0.0F) + { +@@ -239,6 +251,7 @@ + if (loaded && this.options.soundVolume != 0.0F) + { + SoundPoolEntry var7 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str); ++ var7 = ForgeHooksClient.onPlaySound(this, var7, par1Str, par2, par3, par4, par5, par6); + + if (var7 != null && par5 > 0.0F) + { +@@ -274,6 +287,7 @@ + if (loaded && this.options.soundVolume != 0.0F) + { + SoundPoolEntry var4 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str); ++ var4 = ForgeHooksClient.onPlaySoundEffect(this, var4, par1Str, par2, par3); + + if (var4 != null) + { +@@ -293,4 +307,25 @@ + } + } + } ++ ++ /** Getters for private class members **/ ++ public static SoundSystem getSoundSystem() ++ { ++ return sndSystem; ++ } ++ ++ public SoundPool getSoundsPool() ++ { ++ return soundPoolSounds; ++ } ++ ++ public SoundPool getStreamingPool() ++ { ++ return soundPoolStreaming; ++ } ++ ++ public SoundPool getMusicPool() ++ { ++ return soundPoolMusic; ++ } + } diff --git a/forge/patches/minecraft/net/minecraft/src/SoundPool.java.patch b/forge/patches/minecraft/net/minecraft/src/SoundPool.java.patch new file mode 100644 index 000000000..19349d154 --- /dev/null +++ b/forge/patches/minecraft/net/minecraft/src/SoundPool.java.patch @@ -0,0 +1,52 @@ +--- ../src_base/minecraft/net/minecraft/src/SoundPool.java 0000-00-00 00:00:00.000000000 -0000 ++++ ../src_work/minecraft/net/minecraft/src/SoundPool.java 0000-00-00 00:00:00.000000000 -0000 +@@ -2,6 +2,7 @@ + + import java.io.File; + import java.net.MalformedURLException; ++import java.net.URL; + import java.util.ArrayList; + import java.util.HashMap; + import java.util.List; +@@ -33,6 +34,25 @@ + */ + public SoundPoolEntry addSound(String par1Str, File par2File) + { ++ try ++ { ++ return addSound(par1Str, par2File.toURI().toURL()); ++ } ++ catch (MalformedURLException ex) ++ { ++ ex.printStackTrace(); ++ throw new RuntimeException(ex); ++ } ++ } ++ /** ++ * URL version of addSound, as the back-end sound engine has full support for various types of URLs ++ * ++ * @param par1Str The name of the sound to add ++ * @param url The url of the sound resource ++ * @return A SoundPoolEntry for the newly added sound ++ */ ++ public SoundPoolEntry addSound(String par1Str, URL url) ++ { + try + { + String var3 = par1Str; +@@ -53,13 +73,13 @@ + this.nameToSoundPoolEntriesMapping.put(par1Str, new ArrayList()); + } + +- SoundPoolEntry var4 = new SoundPoolEntry(var3, par2File.toURI().toURL()); ++ SoundPoolEntry var4 = new SoundPoolEntry(var3, url); + ((List)this.nameToSoundPoolEntriesMapping.get(par1Str)).add(var4); + this.allSoundPoolEntries.add(var4); + ++this.numberOfSoundPoolEntries; + return var4; + } +- catch (MalformedURLException var5) ++ catch (Exception var5) + { + var5.printStackTrace(); + throw new RuntimeException(var5);