Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TrollReplacer v2.1.2
TrollReplacer.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("TrollReplacer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.1.2.0")] [assembly: AssemblyInformationalVersion("2.1.2")] [assembly: AssemblyProduct("TrollReplacer")] [assembly: AssemblyTitle("TrollReplacer")] [assembly: AssemblyVersion("2.1.2.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace TrollReplacer { [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class AudioSource_SetClip_Patch { private static void Prefix(AudioSource __instance, ref AudioClip __0) { try { AudioClip replacement = Plugin.GetReplacement(__0, ((Component)__instance).gameObject); if ((Object)(object)replacement != (Object)null) { __0 = replacement; } } catch (Exception e) { Plugin.LogErrorOnce(e); } } } [HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[] { typeof(AudioClip), typeof(float) })] internal static class AudioSource_PlayOneShot2_Patch { private static void Prefix(AudioSource __instance, ref AudioClip __0) { try { AudioClip replacement = Plugin.GetReplacement(__0, ((Component)__instance).gameObject); if ((Object)(object)replacement != (Object)null) { __0 = replacement; } } catch (Exception e) { Plugin.LogErrorOnce(e); } } } [HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[] { typeof(AudioClip) })] internal static class AudioSource_PlayOneShot1_Patch { private static void Prefix(AudioSource __instance, ref AudioClip __0) { try { AudioClip replacement = Plugin.GetReplacement(__0, ((Component)__instance).gameObject); if ((Object)(object)replacement != (Object)null) { __0 = replacement; } } catch (Exception e) { Plugin.LogErrorOnce(e); } } } [HarmonyPatch(typeof(AudioSource), "Play", new Type[] { })] internal static class AudioSource_Play_Patch { private static void Prefix(AudioSource __instance) { try { AudioClip clip = __instance.clip; if (!((Object)(object)clip == (Object)null)) { AudioClip replacement = Plugin.GetReplacement(clip, ((Component)__instance).gameObject); if ((Object)(object)replacement != (Object)null) { __instance.clip = replacement; } } } catch (Exception e) { Plugin.LogErrorOnce(e); } } } [HarmonyPatch(typeof(ZSFX), "Awake")] internal static class ZSFX_Awake_Patch { private static void Prefix(ZSFX __instance) { Plugin.ReplaceInZsfx(__instance); } private static void Postfix(ZSFX __instance) { Plugin.ReplaceInZsfx(__instance); } } [HarmonyPatch] internal static class ZSFX_Play_Patch { private static MethodBase Find() { try { return AccessTools.Method(typeof(ZSFX), "Play", new Type[0], (Type[])null); } catch { return null; } } private static bool Prepare() { return Find() != null; } private static MethodBase TargetMethod() { return Find(); } private static void Prefix(ZSFX __instance) { Plugin.ReplaceInZsfx(__instance); } } [HarmonyPatch] internal static class Character_Init_Patch { private static List<MethodBase> Find() { List<MethodBase> list = new List<MethodBase>(); string[] array = new string[2] { "Awake", "Start" }; foreach (string text in array) { MethodBase methodBase = null; try { methodBase = AccessTools.DeclaredMethod(typeof(Character), text, (Type[])null, (Type[])null); } catch { } if (methodBase != null) { list.Add(methodBase); } } return list; } private static bool Prepare() { return Find().Any(); } private static IEnumerable<MethodBase> TargetMethods() { return Find(); } private static void Postfix(Character __instance) { TrollScanner.OnCharacterAwake(__instance); } } [BepInPlugin("com.niclas.trollreplacer.v2", "Troll Replacer", "2.1.2")] public class Plugin : BaseUnityPlugin { private sealed class KeywordSet { private string _raw; private string[] _parts = new string[0]; public string[] Get(string raw) { raw = raw ?? ""; if (raw != _raw) { _raw = raw; List<string> list = new List<string>(); string[] array = raw.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim().ToLowerInvariant(); if (text.Length > 0) { list.Add(text); } } _parts = list.ToArray(); } return _parts; } } public const string PluginGuid = "com.niclas.trollreplacer.v2"; public const string PluginName = "Troll Replacer"; public const string PluginVersion = "2.1.2"; internal static ManualLogSource Log; internal static ConfigEntry<string> MatchKeywords; internal static ConfigEntry<string> ExcludeKeywords; internal static ConfigEntry<string> ReplacementFileName; internal static ConfigEntry<float> VolumeBoost; private static ConfigEntry<int> _configVersion; private const int CurrentConfigVersion = 2; internal static ConfigEntry<bool> ReplaceEffectPrefabs; internal static ConfigEntry<bool> LogUniqueSounds; internal static ConfigEntry<bool> LogAllClipNames; private static string _pluginDir = "."; private static ConfigFile _configFile; private static WavLoader.WavData _data; private static AudioClip _clip; private static int _createFailures; private static int _errors; private static int _matchLogs; private static int _totalReplaced; private const int MaxUniqueLogs = 400; private static readonly HashSet<string> _seen = new HashSet<string>(); private static readonly KeywordSet _match = new KeywordSet(); private static readonly KeywordSet _exclude = new KeywordSet(); private static readonly Type[] PatchTypes = new Type[7] { typeof(AudioSource_SetClip_Patch), typeof(AudioSource_PlayOneShot2_Patch), typeof(AudioSource_PlayOneShot1_Patch), typeof(AudioSource_Play_Patch), typeof(ZSFX_Awake_Patch), typeof(ZSFX_Play_Patch), typeof(Character_Init_Patch) }; private static readonly Type[] SetDataParamTypes = new Type[2] { typeof(float[]), typeof(int) }; private static MethodInfo _setDataMethod; internal static AudioClip Replacement { get { if ((Object)(object)_clip != (Object)null) { return _clip; } if (_data == null || _createFailures >= 3) { return null; } try { AudioClip obj = AudioClip.Create("custom_replacement_clip", _data.Samples.Length, 1, _data.SampleRate, false); if ((Object)(object)obj == (Object)null) { throw new Exception("AudioClip.Create lieferte null"); } if (!CallSetData(obj, _data.Samples)) { throw new Exception("SetData lieferte false"); } ((Object)obj).hideFlags = (HideFlags)61; _clip = obj; } catch (Exception ex) { _createFailures++; Log.LogError((object)("[TrollReplacer] Ersatz-Clip konnte nicht erzeugt werden (Versuch " + _createFailures + "): " + ex.Message)); return null; } return _clip; } } private void Awake() { try { Log = ((BaseUnityPlugin)this).Logger; _configFile = ((BaseUnityPlugin)this).Config; _pluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? "."; MatchKeywords = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MatchKeywords", "troll_attacking", "Kommagetrennte Suchbegriffe (Gross-/Kleinschreibung egal). Ersetzt wird, wenn der Clip-Name ODER der Name des abspielenden Objekts einen davon enthaelt. Standard: NUR das Angriffsbruellen (sfx_troll_attacking) - Treffer/Idle/Alarm/Tod bleiben unangetastet."); ExcludeKeywords = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ExcludeKeywords", "step,walk,foot,run,jump,swim", "Kommagetrennte Begriffe, die NICHT ersetzt werden (z.B. Schrittgeraeusche). Leer = alles ersetzen."); ReplacementFileName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ReplacementFileName", "TROLL.wav", "OPTIONAL: Eigene Audiodatei neben der DLL, die die eingebettete ersetzt. Jede WAV geht (8/16/24/32-bit, Float, Stereo). Ist die Datei nicht da, wird die eingebettete benutzt."); ReplaceEffectPrefabs = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "ReplaceTrollEffectPrefabs", true, "Wenn true: Die Sound-Effekte, die ein Troll ueber seine eigenen Effektlisten (Alarm/Idle/Tod/Treffer) abspielt, werden direkt umgestellt - unabhaengig von den Clip-Namen."); VolumeBoost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "VolumeBoost", 3f, "Verstaerkungsfaktor fuer die Lautstaerke (3.0 = 300% / dreifache Lautstaerke). Wird direkt auf die Samples angewendet, bevor der Clip erzeugt wird. Bei hohen Werten kann es zu Verzerrungen (Clipping) kommen, wenn das Original schon laut war - das ist bei so einem Boost gewollt/normal."); LogUniqueSounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogUniqueSounds", true, "Schreibt jeden verschiedenen Sound (max. 400) einmalig ins Log. Hilft, echte Namen zu finden."); LogAllClipNames = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogAllClipNames", false, "Schreibt JEDEN Abspielvorgang ins Log (sehr viel Text!)."); MigrateOldConfig(); Log.LogInfo((object)("[TrollReplacer] v2.1.2 startet. DLL-Ordner: " + _pluginDir)); Log.LogInfo((object)("[TrollReplacer] Suchbegriffe='" + MatchKeywords.Value + "' Ausschluss='" + ExcludeKeywords.Value + "' EffektPrefabs=" + ReplaceEffectPrefabs.Value + " VolumeBoost=x" + VolumeBoost.Value)); ApplyPatches(); ((MonoBehaviour)this).StartCoroutine(LoadRoutine()); } catch (Exception ex) { if (Log != null) { Log.LogError((object)("[TrollReplacer] Fehler beim Start: " + ex)); } } } private static void MigrateOldConfig() { _configVersion = _configFile.Bind<int>("Internal", "ConfigVersion", 0, "Interner Zaehler fuer automatische Config-Migrationen. Nicht manuell aendern."); if (_configVersion.Value < 2) { if (_configVersion.Value < 2 && MatchKeywords.Value == "troll") { Log.LogInfo((object)"[TrollReplacer] Config-Migration: MatchKeywords war noch der alte Standardwert 'troll' -> auf neuen Standard 'troll_attacking' angehoben. (Eigene Anpassungen waeren hiervon nicht betroffen gewesen.)"); MatchKeywords.Value = "troll_attacking"; } _configVersion.Value = 2; } } private static void ApplyPatches() { int num = 0; StringBuilder stringBuilder = new StringBuilder(); Type[] patchTypes = PatchTypes; foreach (Type type in patchTypes) { try { Harmony.CreateAndPatchAll(type, "com.niclas.trollreplacer.v2"); num++; } catch (Exception ex) { stringBuilder.Append(type.Name).Append(" (").Append(ex.GetType().Name) .Append(": ") .Append(ex.Message) .Append(") "); } } Log.LogInfo((object)("[TrollReplacer] Patches angewendet: " + num + " von " + PatchTypes.Length)); if (stringBuilder.Length > 0) { Log.LogWarning((object)("[TrollReplacer] Folgende Patches sind ausgefallen (der Rest laeuft weiter): " + stringBuilder)); } } private IEnumerator LoadRoutine() { yield return null; yield return null; try { LoadData(); AudioClip replacement = Replacement; if ((Object)(object)replacement != (Object)null) { Log.LogInfo((object)("[TrollReplacer] BEREIT - Ersatz-Sound aktiv (" + replacement.length.ToString("0.00") + " s).")); } else { Log.LogError((object)"[TrollReplacer] NICHT BEREIT - kein Ersatz-Sound verfuegbar, siehe Meldungen oben."); } } catch (Exception ex) { Log.LogError((object)("[TrollReplacer] Fehler beim Laden: " + ex)); } } private static void LoadData() { WavLoader.WavData wavData = null; string text = null; string value = ReplacementFileName.Value; if (!string.IsNullOrEmpty(value)) { string text2 = Path.Combine(_pluginDir, value); if (File.Exists(text2)) { try { wavData = WavLoader.Parse(File.ReadAllBytes(text2)); text = "externe Datei " + text2; } catch (Exception ex) { Log.LogWarning((object)("[TrollReplacer] Externe Datei '" + text2 + "' unbrauchbar (" + ex.Message + "). Nutze stattdessen die eingebettete.")); } } } if (wavData == null) { try { byte[] array = ReadEmbedded(); if (array == null) { Log.LogError((object)"[TrollReplacer] Eingebettete Audiodatei nicht im DLL gefunden."); } else { wavData = WavLoader.Parse(array); text = "eingebettete Datei"; } } catch (Exception ex2) { Log.LogError((object)("[TrollReplacer] Eingebettete Audiodatei unbrauchbar: " + ex2.Message)); } } if (wavData != null) { ApplyVolumeBoost(wavData); _data = wavData; Log.LogInfo((object)("[TrollReplacer] Audio geladen aus " + text + ": " + wavData.Samples.Length + " Samples, " + wavData.SampleRate + " Hz, Original " + wavData.SourceChannels + " Kanal/" + wavData.SourceBits + "-bit, Spitzenpegel nach Boost " + wavData.Peak.ToString("0.00"))); if (wavData.Peak < 0.001f) { Log.LogWarning((object)"[TrollReplacer] ACHTUNG: Die Audiodatei ist praktisch stumm!"); } } } private static void ApplyVolumeBoost(WavLoader.WavData data) { float value = VolumeBoost.Value; if (value == 1f) { return; } float[] samples = data.Samples; int num = 0; float num2 = 0f; for (int i = 0; i < samples.Length; i++) { float num3 = samples[i] * value; if (num3 > 1f) { num3 = 1f; num++; } else if (num3 < -1f) { num3 = -1f; num++; } samples[i] = num3; float num4 = ((num3 < 0f) ? (0f - num3) : num3); if (num4 > num2) { num2 = num4; } } data.Peak = num2; if (num > 0) { Log.LogWarning((object)("[TrollReplacer] Lautstaerke-Boost x" + value.ToString("0.0") + " angewendet - " + num + " von " + samples.Length + " Samples wurden dabei gekappt (haerterer/verzerrter Klang, aber lauter).")); } else { Log.LogInfo((object)("[TrollReplacer] Lautstaerke-Boost x" + value.ToString("0.0") + " angewendet, keine Kappung noetig.")); } } private static byte[] ReadEmbedded() { Assembly assembly = typeof(Plugin).Assembly; Stream manifestResourceStream = assembly.GetManifestResourceStream("TROLL.wav"); if (manifestResourceStream == null) { string[] manifestResourceNames = assembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (text.EndsWith(".wav", StringComparison.OrdinalIgnoreCase)) { manifestResourceStream = assembly.GetManifestResourceStream(text); break; } } } if (manifestResourceStream == null) { return null; } using (manifestResourceStream) { using MemoryStream memoryStream = new MemoryStream(); manifestResourceStream.CopyTo(memoryStream); return memoryStream.ToArray(); } } private static bool CallSetData(AudioClip clip, float[] samples) { if (_setDataMethod == null) { _setDataMethod = typeof(AudioClip).GetMethod("SetData", SetDataParamTypes); if (_setDataMethod == null) { throw new Exception("AudioClip.SetData(float[], int) wurde nicht gefunden."); } } return (bool)_setDataMethod.Invoke(clip, new object[2] { samples, 0 }); } internal static bool AnyContains(string haystackLower, string[] keywords) { if (string.IsNullOrEmpty(haystackLower)) { return false; } for (int i = 0; i < keywords.Length; i++) { if (haystackLower.Contains(keywords[i])) { return true; } } return false; } internal static bool MatchesKeywords(string lower) { return AnyContains(lower, _match.Get(MatchKeywords.Value)); } internal static bool IsExcluded(string lower) { return AnyContains(lower, _exclude.Get(ExcludeKeywords.Value)); } private static string ChainLower(GameObject go) { if ((Object)(object)go == (Object)null) { return ""; } StringBuilder stringBuilder = new StringBuilder(96); Transform val = go.transform; int num = 0; while ((Object)(object)val != (Object)null && num < 4) { stringBuilder.Append(((Object)val).name).Append('/'); val = val.parent; num++; } Transform root = go.transform.root; if ((Object)(object)root != (Object)null) { stringBuilder.Append(((Object)root).name); } return stringBuilder.ToString().ToLowerInvariant(); } internal static AudioClip GetReplacement(AudioClip clip, GameObject owner) { try { if ((Object)(object)clip == (Object)null) { return null; } AudioClip clip2 = _clip; if ((Object)(object)clip2 != (Object)null && clip == clip2) { return null; } string text = ((Object)clip).name ?? ""; string text2 = (((Object)(object)owner != (Object)null) ? ((Object)owner).name : ""); string text3 = ChainLower(owner); if (LogAllClipNames.Value) { Log.LogInfo((object)("[TrollReplacer] Abspielen: clip='" + text + "' objekt='" + text2 + "'")); } LogUnique(text, text2, text3); string lower = text.ToLowerInvariant(); string lower2 = text2.ToLowerInvariant(); if (IsExcluded(lower) || IsExcluded(lower2)) { return null; } bool flag = MatchesKeywords(lower); bool flag2 = !flag && MatchesKeywords(text3); if (!flag && !flag2) { return null; } clip2 = Replacement; if ((Object)(object)clip2 == (Object)null) { return null; } _totalReplaced++; if (_matchLogs < 40) { _matchLogs++; Log.LogInfo((object)("[TrollReplacer] TREFFER #" + _totalReplaced + ": clip='" + text + "' objekt='" + text2 + "' (erkannt ueber " + (flag ? "Clip-Name" : "Objekt-Name") + ") -> ersetzt")); } return clip2; } catch (Exception e) { LogErrorOnce(e); return null; } } internal static void ReplaceInZsfx(ZSFX z) { try { if ((Object)(object)z == (Object)null || z.m_audioClips == null) { return; } GameObject gameObject = ((Component)z).gameObject; for (int i = 0; i < z.m_audioClips.Length; i++) { AudioClip replacement = GetReplacement(z.m_audioClips[i], gameObject); if ((Object)(object)replacement != (Object)null) { z.m_audioClips[i] = replacement; } } } catch (Exception e) { LogErrorOnce(e); } } private static void LogUnique(string clip, string own, string chain) { if (!LogUniqueSounds.Value) { return; } if (_seen.Count >= 400) { if (_seen.Count == 400) { _seen.Add("#limit"); Log.LogInfo((object)("[TrollReplacer] (Limit von " + 400 + " verschiedenen Sounds im Log erreicht.)")); } } else if (_seen.Add(clip + "|" + own)) { Log.LogInfo((object)("[TrollReplacer] Sound gesehen: clip='" + clip + "' objekt='" + own + "' pfad='" + chain + "'")); } } internal static void LogErrorOnce(Exception e) { if (_errors < 5) { _errors++; if (Log != null) { Log.LogError((object)("[TrollReplacer] Interner Fehler (Spiel laeuft weiter): " + e)); } } } } internal static class TrollScanner { private static readonly HashSet<string> _done = new HashSet<string>(); private static readonly HashSet<int> _patchedPrefabs = new HashSet<int>(); private static readonly string[] VoiceHints = new string[14] { "alert", "idle", "death", "dead", "hit", "crit", "backstab", "pain", "taunt", "roar", "voice", "sound", "growl", "scream" }; private static readonly string[] SkipHints = new string[12] { "foot", "step", "walk", "run", "jump", "land", "swim", "water", "slide", "fall", "burn", "fire" }; internal static void OnCharacterAwake(Character c) { try { if ((Object)(object)c == (Object)null) { return; } string text = ((Object)((Component)c).gameObject).name.Replace("(Clone)", "").Trim(); if (!Plugin.MatchesKeywords(text.ToLowerInvariant()) || _done.Contains(text)) { return; } bool flag = (Object)(object)Plugin.Replacement != (Object)null; Plugin.Log.LogInfo((object)("[TrollReplacer] Passendes Wesen gefunden: '" + text + "' - untersuche seine Sound-Effekte:")); int num = 0; Component[] components = ((Component)c).gameObject.GetComponents<Component>(); foreach (Component val in components) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); while (type != null && type != typeof(MonoBehaviour) && type != typeof(object)) { FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType.Name != "EffectList")) { object value = fieldInfo.GetValue(val); if (value != null) { num += HandleList(type.Name, fieldInfo.Name, value, flag); } } } type = type.BaseType; } } if (flag) { _done.Add(text); } Plugin.Log.LogInfo((object)("[TrollReplacer] Untersuchung von '" + text + "' fertig. Direkt umgestellte Prefabs: " + num + (flag ? "" : " (Ersatz-Clip war noch nicht geladen - wird beim naechsten Spawn wiederholt)"))); } catch (Exception e) { Plugin.LogErrorOnce(e); } } private static int HandleList(string compName, string fieldName, object list, bool haveClip) { string haystackLower = fieldName.ToLowerInvariant(); bool flag = Plugin.AnyContains(haystackLower, VoiceHints) && !Plugin.AnyContains(haystackLower, SkipHints); FieldInfo field = list.GetType().GetField("m_effectPrefabs", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Array array = ((field != null) ? (field.GetValue(list) as Array) : null); if (array == null || array.Length == 0) { return 0; } int num = 0; foreach (object item in array) { if (item == null) { continue; } FieldInfo field2 = item.GetType().GetField("m_prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); GameObject val = (GameObject)((field2 != null) ? /*isinst with value type is only supported in some contexts*/: null); if (!((Object)(object)val == (Object)null)) { string name = ((Object)val).name; string lower = name.ToLowerInvariant(); bool num2 = val.GetComponentsInChildren<ZSFX>(true).Length != 0 || val.GetComponentsInChildren<AudioSource>(true).Length != 0; bool flag2 = false; string text; if (!num2) { text = "kein Audio"; } else if (!flag) { text = "keine Stimm-Liste, bleibt"; } else if (Plugin.IsExcluded(lower)) { text = "ausgeschlossen (Schritt/Lauf), bleibt"; } else if (Plugin.MatchesKeywords(lower)) { text = "Name passt -> ersetzen"; flag2 = true; } else { text = "Suchbegriff passt nicht, bleibt unangetastet"; } Plugin.Log.LogInfo((object)("[TrollReplacer] " + compName + "." + fieldName + ": '" + name + "' -> " + text)); if (flag2 && haveClip && Plugin.ReplaceEffectPrefabs.Value && PatchPrefab(val)) { num++; } } } return num; } private static bool PatchPrefab(GameObject pf) { int instanceID = ((Object)pf).GetInstanceID(); if (_patchedPrefabs.Contains(instanceID)) { return false; } AudioClip replacement = Plugin.Replacement; if ((Object)(object)replacement == (Object)null) { return false; } int num = 0; ZSFX[] componentsInChildren = pf.GetComponentsInChildren<ZSFX>(true); foreach (ZSFX val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && val.m_audioClips != null) { for (int j = 0; j < val.m_audioClips.Length; j++) { val.m_audioClips[j] = replacement; num++; } } } AudioSource[] componentsInChildren2 = pf.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { AudioClip clip = val2.clip; if ((Object)(object)clip != (Object)null && clip != replacement) { val2.clip = replacement; num++; } } } _patchedPrefabs.Add(instanceID); Plugin.Log.LogInfo((object)("[TrollReplacer] -> Prefab '" + ((Object)pf).name + "' direkt umgestellt (" + num + " Clips).")); return true; } } internal static class WavLoader { internal sealed class WavData { public float[] Samples; public int SampleRate; public int SourceChannels; public int SourceBits; public float Peak; } private static string Tag(byte[] b, int pos) { return new string(new char[4] { (char)b[pos], (char)b[pos + 1], (char)b[pos + 2], (char)b[pos + 3] }); } public static WavData Parse(byte[] b) { if (b == null || b.Length < 44) { throw new Exception("Datei ist zu klein, um eine WAV zu sein."); } if (Tag(b, 0) != "RIFF" || Tag(b, 8) != "WAVE") { throw new Exception("Kein gueltiges RIFF/WAVE-Format (ist es evtl. eine umbenannte MP3/OGG?)."); } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; bool flag = false; int num5 = -1; long num6 = 0L; long num7 = 12L; while (num7 + 8 <= b.Length) { string text = Tag(b, (int)num7); long num8 = BitConverter.ToUInt32(b, (int)num7 + 4); long num9 = num7 + 8; if (text == "fmt " && !flag) { if (num8 < 16 || num9 + 16 > b.Length) { throw new Exception("fmt-Chunk ist beschaedigt."); } num = BitConverter.ToUInt16(b, (int)num9); num2 = BitConverter.ToUInt16(b, (int)num9 + 2); num3 = BitConverter.ToInt32(b, (int)num9 + 4); num4 = BitConverter.ToUInt16(b, (int)num9 + 14); if (num == 65534 && num8 >= 26 && num9 + 26 <= b.Length) { num = BitConverter.ToUInt16(b, (int)num9 + 24); } flag = true; } else if (text == "data" && num5 < 0) { num5 = (int)num9; num6 = Math.Min(num8, b.Length - num9); } long num10 = num9 + num8 + (num8 & 1); if (num10 <= num7 || num10 > b.Length) { break; } num7 = num10; } if (!flag) { throw new Exception("Kein fmt-Chunk gefunden."); } if (num5 < 0 || num6 <= 0) { throw new Exception("Kein Audio-Datenblock (data-Chunk) gefunden."); } if (num2 < 1 || num2 > 32) { throw new Exception("Ungueltige Kanalzahl: " + num2); } if (num3 < 1000 || num3 > 384000) { throw new Exception("Ungueltige Samplerate: " + num3); } bool flag2 = num == 3; bool num11 = num == 1; if (!num11 && !flag2) { throw new Exception("Nicht unterstuetztes WAV-Format (Tag " + num + "). Bitte als PCM speichern."); } if (num11 && num4 != 8 && num4 != 16 && num4 != 24 && num4 != 32) { throw new Exception("Nicht unterstuetzte Bittiefe: " + num4); } if (flag2 && num4 != 32 && num4 != 64) { throw new Exception("Nicht unterstuetzte Float-Bittiefe: " + num4); } int num12 = num4 / 8; int num13 = num12 * num2; long num14 = num6 / num13; if (num14 < 1) { throw new Exception("Audio enthaelt keine Samples."); } if (num14 > 50000000) { throw new Exception("Audio ist unrealistisch lang."); } float[] array = new float[num14]; float num15 = 0f; long num16 = num5; for (long num17 = 0L; num17 < num14; num17++) { double num18 = 0.0; for (int i = 0; i < num2; i++) { int num19 = (int)num16; float num20; if (flag2) { num20 = ((num4 == 32) ? BitConverter.ToSingle(b, num19) : ((float)BitConverter.ToDouble(b, num19))); if (float.IsNaN(num20) || float.IsInfinity(num20)) { num20 = 0f; } } else { switch (num4) { case 8: num20 = (float)(b[num19] - 128) / 128f; break; case 16: num20 = (float)BitConverter.ToInt16(b, num19) / 32768f; break; case 24: { int num21 = b[num19] | (b[num19 + 1] << 8) | (b[num19 + 2] << 16); if ((num21 & 0x800000) != 0) { num21 |= -16777216; } num20 = (float)num21 / 8388608f; break; } default: num20 = (float)BitConverter.ToInt32(b, num19) / 2.1474836E+09f; break; } } num18 += (double)num20; num16 += num12; } float num22 = (float)(num18 / (double)num2); if (num22 > 1f) { num22 = 1f; } else if (num22 < -1f) { num22 = -1f; } array[num17] = num22; float num23 = ((num22 < 0f) ? (0f - num22) : num22); if (num23 > num15) { num15 = num23; } } return new WavData { Samples = array, SampleRate = num3, SourceChannels = num2, SourceBits = num4, Peak = num15 }; } } }