diff --git a/utils/ResourcesPatch.cs b/utils/ResourcesPatch.cs index 225e1fd..a749964 100644 --- a/utils/ResourcesPatch.cs +++ b/utils/ResourcesPatch.cs @@ -4,13 +4,32 @@ using NeoModLoader.services; using UnityEngine; using UnityEngine.U2D; +using FMOD; using Object = UnityEngine.Object; +using FMODUnity; +using ReflectionUtility; +using FMOD.Studio; +using System.Reflection.Emit; +using System.Runtime.Remoting.Channels; +using Newtonsoft.Json; namespace NeoModLoader.utils; /// /// This class is used to patch resources. /// +public struct WavContainer +{ + public string Path; + public bool _3D; + public float Volume; + public WavContainer(string Path, bool _3D, float Volume) + { + this.Path = Path; + this._3D = _3D; + this.Volume = Volume; + } +} public static class ResourcesPatch { private static ResourceTree tree; @@ -26,6 +45,9 @@ public static Dictionary GetAllPatchedResources() { return tree.direct_objects; } + public static Dictionary AudioWavLibrary = new Dictionary(); + public static FMOD.System fmodSystem; + public static ChannelGroup masterChannelGroup; /// /// Patch a resource to the tree at runtime. @@ -36,9 +58,21 @@ public static void PatchResource(string pPath, Object pObject) { tree.Add(pPath, pObject); } - + static void InitializeFMODSystem() + { + if (RuntimeManager.StudioSystem.getCoreSystem(out fmodSystem) != FMOD.RESULT.OK) + { + LogService.LogError("Failed to initialize FMOD Core System!"); + return; + } + if (fmodSystem.getMasterChannelGroup(out masterChannelGroup) != FMOD.RESULT.OK) + { + LogService.LogError("Failed to retrieve master channel group!"); + } + } internal static void Initialize() { + InitializeFMODSystem(); tree = new ResourceTree(); SpriteAtlas atlas = Resources.FindObjectsOfTypeAll() .FirstOrDefault(x => x.name == "SpriteAtlasUI"); @@ -84,11 +118,53 @@ public static Object[] LoadResourceFile(ref string path, ref string pLowerPath) { if (pLowerPath.EndsWith(".png") || pLowerPath.EndsWith(".jpg") || pLowerPath.EndsWith(".jpeg")) return SpriteLoadUtils.LoadSprites(path); + if (pLowerPath.EndsWith(".wav")) + { + LoadWavFile(path); + } return new Object[] { LoadTextAsset(path) }; } + //doesnt return anything, simply adds the wav to the wav library that contains all the custom sounds + private static void LoadWavFile(string path) + { + string Name = Path.GetFileNameWithoutExtension(path); + WavContainer container = JsonConvert.DeserializeObject(File.ReadAllText(Path.GetDirectoryName(path) + "/" + Name + ".json")); + AudioWavLibrary.Add(Name, container); + } + [HarmonyPrefix] + [HarmonyPatch(typeof(MusicBox), nameof(MusicBox.playSound), new Type[] {typeof(string), typeof(float), typeof(float), typeof(bool), typeof(bool) })] + public static bool LoadCustomSound(string pSoundPath, float pX, float pY, bool pGameViewOnly) + { + if (!MusicBox.sounds_on) + { + return false; + } + if (pGameViewOnly && World.world.qualityChanger.lowRes) + { + return false; + } + if (!AudioWavLibrary.ContainsKey(pSoundPath)) { return true; } + WavContainer WAV = AudioWavLibrary[pSoundPath]; + if(fmodSystem.createSound(WAV.Path, WAV._3D ? MODE._3D : MODE._2D, out FMOD.Sound sound) != RESULT.OK) + { + UnityEngine.Debug.Log($"Unable to play sound {pSoundPath}!"); + } + Vector3 listenerPosition = new Vector3(Camera.main.transform.position.x, Camera.main.transform.position.y, Camera.main.orthographicSize); + Vector3 sourcePosition = new(pX, pY, 0); + fmodSystem.playSound(sound, masterChannelGroup, false, out Channel channel); + if (WAV._3D) + { + VECTOR vel = new VECTOR() { x = listenerPosition.x - pX, y = listenerPosition.y - pY, z = 0 }; + VECTOR pos = new VECTOR() { x = pX, y = pY, z = 0 }; + channel.set3DAttributes(ref pos, ref vel); + } + float normalizedDistance = Mathf.Clamp01(Vector3.Distance(sourcePosition, listenerPosition) / WAV.Volume); + channel.setVolume(1f - normalizedDistance); + return false; + } private static TextAsset LoadTextAsset(string path) {