using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Localizer; using NVorbis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("OutwardModTemplate")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OutwardModTemplate")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c5450fe0-edcf-483f-b9ea-4b1ef9d36da7")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = "")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace SideLoader.DialogueAudioAddon { public static class DialogueAudioAddonConfig { public static ConfigEntry DebugLogClipNames; public static void Bind(ConfigFile config) { DebugLogClipNames = config.Bind("Debug", "LogDialogueClipNames", false, "If active, log the exact name of each dialogue clip played (useful to find the right sound file name to use.)."); } } [BepInPlugin("Tchernobill.DialogueAudioAddon", "Dialogue Audio Addon", "1.0.1")] public class DialogueAudioAddonPlugin : BaseUnityPlugin { public const string GUID = "Tchernobill.DialogueAudioAddon"; public const string NAME = "Dialogue Audio Addon"; public const string VERSION = "1.0.1"; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown DialogueAudioAddonConfig.Bind(((BaseUnityPlugin)this).Config); Harmony val = new Harmony("Tchernobill.DialogueAudioAddon"); val.PatchAll(); } } public static class DialogueAudioRegistry { private static readonly Dictionary Clips = new Dictionary(); public static void Register(string clipName, AudioClip clip) { if (!string.IsNullOrEmpty(clipName) && !((Object)(object)clip == (Object)null)) { if (Clips.ContainsKey(clipName) && DialogueAudioAddonConfig.DebugLogClipNames.Value) { SL.Log("[DialogueAudioAddon] Remplacement override for '" + clipName + "' (multiple replacements!)."); } Clips[clipName] = clip; if (DialogueAudioAddonConfig.DebugLogClipNames.Value) { SL.Log("[DialogueAudioAddon] Dialogue clip stored : '" + clipName + "'"); } } } public static bool TryGetReplacement(string originalClipName, out AudioClip replacement) { return Clips.TryGetValue(originalClipName, out replacement); } } public static class OggAudioClipLoader { public static AudioClip LoadFromFile(string filePath, string clipName) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown try { VorbisReader val = new VorbisReader(filePath); try { int channels = val.Channels; int sampleRate = val.SampleRate; List list = new List(); float[] array = new float[channels * sampleRate]; int num; while ((num = val.ReadSamples(array, 0, array.Length)) > 0) { for (int i = 0; i < num; i++) { list.Add(array[i]); } } AudioClip val2 = AudioClip.Create(clipName, list.Count / channels, channels, sampleRate, false); val2.SetData(list.ToArray(), 0); return val2; } finally { ((IDisposable)val)?.Dispose(); } } catch (Exception ex) { SL.LogWarning("[DialogueAudioAddon] OGG decoding error '" + filePath + "': " + ex.Message); return null; } } } public static class OggPackScanner { public static void ScanAndRegisterAll() { string[] directories = Directory.GetDirectories(Paths.PluginPath); foreach (string path in directories) { string text = Path.Combine(path, "Sideloader"); if (!Directory.Exists(text)) { continue; } string path2 = Path.Combine(text, "AudioClip"); if (!Directory.Exists(path2)) { continue; } string[] files = Directory.GetFiles(path2, "*.ogg"); foreach (string text2 in files) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2); AudioClip val = OggAudioClipLoader.LoadFromFile(text2, fileNameWithoutExtension); if ((Object)(object)val != (Object)null) { DialogueAudioRegistry.Register(fileNameWithoutExtension, val); } } } } } } namespace SideLoader.DialogueAudioAddon.Patches { [HarmonyPatch(typeof(CustomAudio), "FinalizeAudioClip")] public static class Patch_CustomAudio_FinalizeAudioClip { [HarmonyPostfix] public static void Postfix(string name, AudioClip __result) { if ((Object)(object)__result != (Object)null) { DialogueAudioRegistry.Register(name, __result); } } } [HarmonyPatch(typeof(DialogueAudio), "SetSound")] public static class Patch_DialogueAudio_SetSound { [HarmonyPrefix] public static void Prefix(ref AudioClip _clip) { if ((Object)(object)_clip == (Object)null) { return; } if (DialogueAudioAddonConfig.DebugLogClipNames.Value) { SL.Log("[DialogueAudioAddon] Reading dialogue : '" + ((Object)_clip).name + "'"); } if (DialogueAudioRegistry.TryGetReplacement(((Object)_clip).name, out var replacement)) { if (DialogueAudioAddonConfig.DebugLogClipNames.Value) { SL.Log("[DialogueAudioAddon] Replacing dialogue '" + ((Object)_clip).name + "'."); } _clip = replacement; } } } [HarmonyPatch(typeof(SNPCManager), "SNPCTalking", new Type[] { typeof(Character), typeof(string), typeof(DialogueLocalization), typeof(bool) })] public class Patch_SNPCManager_SNPCTalking { [HarmonyPrefix] public unsafe static void Prefix(ref SNPCManager __instance, ref Character _player, ref string _npcLocKey, ref DialogueLocalization _dialogueData, ref bool _isVinicity) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (_dialogueData == null) { return; } bool flag = !string.IsNullOrEmpty(_dialogueData.UniqueAudioName) && _dialogueData.UniqueAudioName.Length > 1; bool flag2 = _dialogueData.EmoteTags.Length != 0; if (!__instance.DialogueSNPCs.ContainsKey(_npcLocKey) && _dialogueData.Key != null && _dialogueData.Key != "") { string lastLoadedLanguage = DialogueAssetsManager.Instance.m_lastLoadedLanguage; DLCs dLC = _dialogueData.DLC; string arg = (((int)dLC == 0) ? string.Empty : ((object)(*(DLCs*)(&dLC))/*cast due to .constrained prefix*/).ToString()); string key = $"{lastLoadedLanguage}{arg}"; DialogueBundleData value; bool flag3 = DialogueAssetsManager.Instance.m_loadedBundleData.TryGetValue(key, out value) && (Object)(object)value.DiagData != (Object)null && ((DictionaryExt)(object)value.DiagData.DataDict).ContainsKey(_dialogueData.Key); string originalClipName = $"dlg_&{_dialogueData.Key}"; if (!flag3 && DialogueAudioRegistry.TryGetReplacement(originalClipName, out var replacement)) { __instance.m_diagAudio.SetSound(replacement); __instance.m_diagAudio.Play(); } } } } [HarmonyPatch(typeof(VicinityDialoguePanel), "ShowDialogue")] public class Patch_VicinityDialoguePanel_ShowDialogue { [HarmonyPrefix] public static void Prefix(ref VicinityDialoguePanel __instance, ref string _instigatorUID, ref string _dialogueLocKey, ref string _npcLocKey) { SL.Log("[DialogueAudioAddon] Patch_VicinityDialoguePanel_ShowDialogue '" + _instigatorUID + "' '" + _dialogueLocKey + "' '" + _npcLocKey + "'."); } } }