using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
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 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 = ".NET Framework 4.8.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace SideLoader.DialogueAudioAddon
{
internal static class AudioFormatsBridge
{
private static Func<string, bool> s_contains;
private static Action<string> s_prefetch;
private static Func<string, AudioClip> s_getLoaded;
private static Func<string, AudioClip> s_getNow;
private static bool s_bound;
public static bool Available { get; private set; }
private static void Bind()
{
if (s_bound)
{
return;
}
s_bound = true;
Type type = Type.GetType("Tchernobill.AudioFormats.LazyAudioClips, AudioFormats", throwOnError: false);
if (type == null)
{
return;
}
try
{
s_contains = (Func<string, bool>)Delegate.CreateDelegate(typeof(Func<string, bool>), type.GetMethod("Contains", BindingFlags.Static | BindingFlags.Public));
s_prefetch = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), type.GetMethod("Prefetch", BindingFlags.Static | BindingFlags.Public));
s_getLoaded = (Func<string, AudioClip>)Delegate.CreateDelegate(typeof(Func<string, AudioClip>), type.GetMethod("GetLoaded", BindingFlags.Static | BindingFlags.Public));
s_getNow = (Func<string, AudioClip>)Delegate.CreateDelegate(typeof(Func<string, AudioClip>), type.GetMethod("GetNow", BindingFlags.Static | BindingFlags.Public));
Available = true;
}
catch (Exception ex)
{
SL.LogWarning("[DialogueAudioAddon] Audio Formats is installed but its lazy clip index could not be reached (" + ex.Message + "). Large packs will keep loading up front.");
}
}
public static bool Knows(string clipName)
{
Bind();
return Available && s_contains(clipName);
}
public static void Prefetch(string clipName)
{
Bind();
if (Available)
{
s_prefetch(clipName);
}
}
public static AudioClip GetLoaded(string clipName)
{
Bind();
return Available ? s_getLoaded(clipName) : null;
}
public static AudioClip GetNow(string clipName)
{
Bind();
return Available ? s_getNow(clipName) : null;
}
}
public static class DialogueAudioAddonConfig
{
public static ConfigEntry<bool> DebugLogClipNames;
public static void Bind(ConfigFile config)
{
DebugLogClipNames = config.Bind<bool>("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.2")]
public class DialogueAudioAddonPlugin : BaseUnityPlugin
{
public const string GUID = "Tchernobill.DialogueAudioAddon";
public const string NAME = "Dialogue Audio Addon";
public const string VERSION = "1.0.2";
public static DialogueAudioAddonPlugin Instance { get; private set; }
private void Awake()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
Instance = this;
DialogueAudioAddonConfig.Bind(((BaseUnityPlugin)this).Config);
Harmony val = new Harmony("Tchernobill.DialogueAudioAddon");
val.PatchAll();
}
}
public static class DialogueAudioRegistry
{
private static readonly Dictionary<string, AudioClip> Clips = new Dictionary<string, AudioClip>();
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, bool decodeNow = false)
{
if (Clips.TryGetValue(originalClipName, out replacement))
{
return true;
}
replacement = AudioFormatsBridge.GetLoaded(originalClipName);
if ((Object)(object)replacement != (Object)null)
{
return true;
}
if (!decodeNow || !AudioFormatsBridge.Knows(originalClipName))
{
return false;
}
replacement = AudioFormatsBridge.GetNow(originalClipName);
if ((Object)(object)replacement != (Object)null)
{
SL.Log("[DialogueAudioAddon] Decoded '" + originalClipName + "' on the spot: no prefetch covered that name.");
}
return (Object)(object)replacement != (Object)null;
}
public static void Prefetch(string clipName)
{
if (!string.IsNullOrEmpty(clipName) && !Clips.ContainsKey(clipName))
{
AudioFormatsBridge.Prefetch(clipName);
}
}
public static bool HasReplacement(string originalClipName)
{
return Clips.ContainsKey(originalClipName) || AudioFormatsBridge.Knows(originalClipName);
}
}
public static class PendingDialogueAudio
{
public static string ClipName { get; private set; }
public static bool HasClipName => !string.IsNullOrEmpty(ClipName);
public static void Set(string clipName)
{
ClipName = clipName;
}
public static void Clear()
{
ClipName = null;
}
public static bool Consume(out string clipName, out AudioClip clip)
{
clipName = ClipName;
Clear();
clip = null;
if (string.IsNullOrEmpty(clipName))
{
return false;
}
DialogueAudioRegistry.TryGetReplacement(clipName, out clip, decodeNow: true);
return (Object)(object)clip != (Object)null;
}
}
}
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 + "'");
}
string clipName;
AudioClip clip;
if (DialogueAudioRegistry.TryGetReplacement(((Object)_clip).name, out var replacement, decodeNow: true))
{
if (DialogueAudioAddonConfig.DebugLogClipNames.Value)
{
SL.Log("[DialogueAudioAddon] Replacing dialogue '" + ((Object)_clip).name + "'.");
}
_clip = replacement;
PendingDialogueAudio.Clear();
}
else if (PendingDialogueAudio.Consume(out clipName, out clip))
{
if (DialogueAudioAddonConfig.DebugLogClipNames.Value)
{
SL.Log("[DialogueAudioAddon] Replacing bark '" + ((Object)_clip).name + "' with pending '" + clipName + "'.");
}
_clip = clip;
}
}
}
[HarmonyPatch(typeof(SNPCManager), "SNPCTalking", new Type[]
{
typeof(Character),
typeof(string),
typeof(DialogueLocalization),
typeof(bool)
})]
public class Patch_SNPCManager_SNPCTalking
{
private static int s_lineToken;
private const int MaxWaitFrames = 60;
[HarmonyPrefix]
public static void Prefix(ref SNPCManager __instance, ref Character _player, ref string _npcLocKey, ref DialogueLocalization _dialogueData, ref bool _isVinicity)
{
PendingDialogueAudio.Clear();
s_lineToken++;
if (_dialogueData == null || string.IsNullOrEmpty(_dialogueData.Key))
{
return;
}
string text = $"dlg_&{_dialogueData.Key}";
DialogueAudioRegistry.Prefetch(text);
if (!string.IsNullOrEmpty(_dialogueData.UniqueAudioName) && _dialogueData.UniqueAudioName.Length > 1)
{
DialogueAudioRegistry.Prefetch(_dialogueData.UniqueAudioName);
DialogueAudioRegistry.Prefetch($"dlg_&{_dialogueData.UniqueAudioName}");
}
else
{
if (!DialogueAudioRegistry.HasReplacement(text))
{
return;
}
if (_dialogueData.EmoteTags != null && _dialogueData.EmoteTags.Length != 0)
{
PendingDialogueAudio.Set(text);
if (DialogueAudioAddonConfig.DebugLogClipNames.Value)
{
SL.Log("[DialogueAudioAddon] Pending replacement '" + text + "' for '" + _npcLocKey + "' (bark expected).");
}
}
else if ((Object)(object)__instance.m_diagAudio != (Object)null)
{
PlayWhenReady(__instance.m_diagAudio, text, _npcLocKey);
}
}
}
private static void PlayWhenReady(DialogueAudio diagAudio, string clipName, string npcLocKey)
{
if (DialogueAudioRegistry.TryGetReplacement(clipName, out var replacement))
{
Play(diagAudio, replacement, clipName, npcLocKey);
return;
}
DialogueAudioAddonPlugin instance = DialogueAudioAddonPlugin.Instance;
if (!Object.op_Implicit((Object)(object)instance))
{
if (DialogueAudioRegistry.TryGetReplacement(clipName, out var replacement2, decodeNow: true))
{
Play(diagAudio, replacement2, clipName, npcLocKey);
}
}
else
{
((MonoBehaviour)instance).StartCoroutine(PlayWhenReadyCoroutine(diagAudio, clipName, npcLocKey, s_lineToken));
}
}
private static IEnumerator PlayWhenReadyCoroutine(DialogueAudio diagAudio, string clipName, string npcLocKey, int token)
{
for (int frame = 0; frame < 60; frame++)
{
yield return null;
if (token != s_lineToken || !Object.op_Implicit((Object)(object)diagAudio))
{
yield break;
}
if (DialogueAudioRegistry.TryGetReplacement(clipName, out var clip))
{
Play(diagAudio, clip, clipName, npcLocKey);
yield break;
}
clip = null;
}
if (token == s_lineToken && Object.op_Implicit((Object)(object)diagAudio) && DialogueAudioRegistry.TryGetReplacement(clipName, out var late, decodeNow: true))
{
Play(diagAudio, late, clipName, npcLocKey);
}
}
private static void Play(DialogueAudio diagAudio, AudioClip clip, string clipName, string npcLocKey)
{
diagAudio.SetSound(clip);
diagAudio.Play();
if (DialogueAudioAddonConfig.DebugLogClipNames.Value)
{
SL.Log("[DialogueAudioAddon] Played '" + clipName + "' directly for '" + npcLocKey + "' (no game audio expected).");
}
}
}
[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)
{
if (DialogueAudioAddonConfig.DebugLogClipNames.Value)
{
SL.Log("[DialogueAudioAddon] VicinityDialoguePanel.ShowDialogue '" + _instigatorUID + "' '" + _dialogueLocKey + "' '" + _npcLocKey + "'.");
}
}
}
}