using 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.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BinderDyn.audio; using BinderDyn.config; using BinderDyn.model; using BinderDyn.patch; using BinderDyn.service; using Concentus; using Concentus.Oggfile; using GermanBrainrot.NetcodePatcher; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("GermanBrainrot")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("German meme streamer sounds synced to creature audio")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+e4868d1d8bb0448fb7f25eaf67a2444720a00431")] [assembly: AssemblyProduct("GermanBrainrot")] [assembly: AssemblyTitle("GermanBrainrot")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] internal class { static () { } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 BinderDyn { internal static class NetcodeRpcInitializer { private static bool _initialized; public static void InitializeAssembly() { if (_initialized) { return; } _initialized = true; ManualLogSource val = Logger.CreateLogSource("GermanBrainrot"); int num = 0; Type[] loadableTypes = GetLoadableTypes(Assembly.GetExecutingAssembly()); foreach (Type type in loadableTypes) { MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (ShouldInvokeInitializer(methodInfo) && methodInfo.IsStatic) { try { methodInfo.Invoke(null, null); num++; val.LogInfo((object)("Registered netcode via " + type.Name + "." + methodInfo.Name)); } catch (Exception arg) { val.LogError((object)$"Failed netcode init {type.Name}.{methodInfo.Name}: {arg}"); } } } } if (num == 0) { val.LogWarning((object)"No netcode RPC initializer methods ran. Build with netcode-patch enabled (do not use SkipNetcodePatch=true for release builds)."); } } public static void InitializeInstance(NetworkBehaviour behaviour) { ((object)behaviour).GetType().GetMethod("__initializeVariables", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(behaviour, null); } private static bool ShouldInvokeInitializer(MethodInfo method) { if (method.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0) { return true; } return method.Name.StartsWith("InitializeRPCS_", StringComparison.Ordinal); } private static Type[] GetLoadableTypes(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type type) => type != null).ToArray(); } } } [BepInPlugin("GermanBrainrot", "GermanBrainrot", "1.0.0")] public class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("GermanBrainrot"); public static Plugin Instance { get; private set; } public static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; public Plugin() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown Instance = this; } private void Awake() { NetcodeRpcInitializer.InitializeAssembly(); SoundPackService.Load(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location)); Log.LogInfo((object)"Applying patches..."); _harmony.PatchAll(typeof(EnemyPrefabPatch)); _harmony.PatchAll(typeof(CreatureSoundPatch)); Log.LogInfo((object)"GermanBrainrot loaded."); } } public static class PluginInfo { public const string PLUGIN_GUID = "GermanBrainrot"; public const string PLUGIN_NAME = "GermanBrainrot"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace BinderDyn.service { public static class CreatureProfileTestHelper { public static bool ShouldTriggerForClip(CreatureProfile profile, string? clipName) { return profile.ShouldTriggerForClip(clipName); } } public static class SoundPackService { private static readonly JsonSerializerSettings ProfileJsonSettings = new JsonSerializerSettings { ContractResolver = (IContractResolver)new CamelCasePropertyNamesContractResolver() }; private static readonly Dictionary ProfilesByEnemyType = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary> ClipsByProfileId = new Dictionary>(); private static readonly Random Random = new Random(); public static string PluginDirectory { get; private set; } = string.Empty; public static string AudioRootDirectory { get; private set; } = string.Empty; public static IReadOnlyCollection AllProfiles => ProfilesByEnemyType.Values; public static void Load(string pluginPath) { string text = (PluginDirectory = (Directory.Exists(pluginPath) ? pluginPath : Path.GetDirectoryName(pluginPath))); AudioRootDirectory = Path.Combine(text, "audio"); ProfilesByEnemyType.Clear(); ClipsByProfileId.Clear(); List list = LoadProfilesFile(text); ModConfig.Bind(((BaseUnityPlugin)Plugin.Instance).Config, list); foreach (CreatureProfile item in list) { ProfilesByEnemyType[item.EnemyType] = item; ClipsByProfileId[item.Id] = ScanPackFolder(item); } Plugin.Log.LogInfo((object)$"Loaded {list.Count} creature sound profile(s)."); } private static List LoadProfilesFile(string pluginDirectory) { string text = Path.Combine(pluginDirectory, "config", "creature-profiles.json"); if (!File.Exists(text)) { text = Path.Combine(pluginDirectory, "creature-profiles.json"); } if (!File.Exists(text)) { Plugin.Log.LogWarning((object)("creature-profiles.json not found at " + text)); return new List(); } try { string text2 = File.ReadAllText(text); return JsonConvert.DeserializeObject(text2, ProfileJsonSettings)?.Profiles ?? new List(); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to parse creature-profiles.json: " + ex.Message)); return new List(); } } private static IReadOnlyList ScanPackFolder(CreatureProfile profile) { string text = Path.Combine(AudioRootDirectory, profile.SoundPackFolder.Replace('/', Path.DirectorySeparatorChar)); if (!Directory.Exists(text)) { Plugin.Log.LogWarning((object)("Sound pack folder missing for " + profile.Id + ": " + text)); return Array.Empty(); } List list = Directory.EnumerateFiles(text, "*.*", SearchOption.TopDirectoryOnly).Where(delegate(string path) { string extension = Path.GetExtension(path); return extension.Equals(".opus", StringComparison.OrdinalIgnoreCase) || extension.Equals(".wav", StringComparison.OrdinalIgnoreCase); }).OrderBy((string path) => path, StringComparer.OrdinalIgnoreCase) .ToList(); if (list.Count == 0) { Plugin.Log.LogWarning((object)("No .opus or .wav clips found for " + profile.Id + " in " + text)); } else { Plugin.Log.LogInfo((object)$"Found {list.Count} clip(s) for {profile.Id} in {text}"); } return list; } public static CreatureProfile? GetProfileForEnemy(EnemyAI enemy) { if ((Object)(object)enemy == (Object)null) { return null; } string name = ((object)enemy).GetType().Name; CreatureProfile value; return ProfilesByEnemyType.TryGetValue(name, out value) ? value : null; } public static bool IsProfileActive(CreatureProfile profile) { IReadOnlyList value; return ModConfig.IsProfileEnabled(profile) && ClipsByProfileId.TryGetValue(profile.Id, out value) && value.Count > 0; } public static string? PickRandomClip(CreatureProfile profile, string? excludePath = null) { if (!ClipsByProfileId.TryGetValue(profile.Id, out var value) || value.Count == 0) { return null; } return PickRandomClipFromList(value, excludePath, Random); } public static string? PickRandomClipFromList(IReadOnlyList clips, string? excludePath, Random random) { if (clips.Count == 0) { return null; } if (clips.Count == 1) { return clips[0]; } List list = ((!string.IsNullOrEmpty(excludePath)) ? clips.Where((string clip) => !clip.Equals(excludePath, StringComparison.OrdinalIgnoreCase)).ToList() : clips.ToList()); if (list.Count == 0) { list = clips.ToList(); } return list[random.Next(list.Count)]; } public static bool ShouldTrigger(CreatureProfile profile, string? clipName) { return IsProfileActive(profile) && profile.ShouldTriggerForClip(clipName); } } } namespace BinderDyn.patch { [HarmonyPatch(typeof(AudioSource))] public static class CreatureSoundPatch { [HarmonyPrefix] [HarmonyPatch("PlayOneShot", new Type[] { typeof(AudioClip) })] private static bool OnPlayOneShotClip(AudioSource __instance, AudioClip clip) { return HandleCreatureSound(__instance, clip); } [HarmonyPrefix] [HarmonyPatch("PlayOneShot", new Type[] { typeof(AudioClip), typeof(float) })] private static bool OnPlayOneShotClipVolume(AudioSource __instance, AudioClip clip, float volumeScale) { return HandleCreatureSound(__instance, clip); } private static bool HandleCreatureSound(AudioSource audioSource, AudioClip? clip) { if ((Object)(object)clip == (Object)null || (Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost) { return true; } EnemyAI componentInParent = ((Component)audioSource).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return true; } CreatureProfile profileForEnemy = SoundPackService.GetProfileForEnemy(componentInParent); if (profileForEnemy == null || !SoundPackService.ShouldTrigger(profileForEnemy, ((Object)clip).name)) { return true; } CreatureAudioStream component = ((Component)componentInParent).GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogWarning((object)("CreatureAudioStream missing on " + ((object)componentInParent).GetType().Name)); return ModConfig.PlayAlongsideVanilla.Value; } if (component.IsStreaming) { return ModConfig.PlayAlongsideVanilla.Value; } string text = SoundPackService.PickRandomClip(profileForEnemy, component.LastPlayedClipPath); if (text == null) { return true; } component.StreamOpusFromFile(text); return ModConfig.PlayAlongsideVanilla.Value; } } [HarmonyPatch(typeof(MenuManager), "Start")] public static class EnemyPrefabPatch { [HarmonyPostfix] private static void InjectCreatureAudioStream() { if ((Object)(object)NetworkManager.Singleton == (Object)null) { Plugin.Log.LogWarning((object)"NetworkManager not available during MenuManager.Start"); return; } HashSet hashSet = SoundPackService.AllProfiles.Select((CreatureProfile profile) => profile.EnemyType).ToHashSet(); int num = 0; foreach (NetworkPrefab prefab in NetworkManager.Singleton.NetworkConfig.Prefabs.Prefabs) { if (!((Object)(object)prefab?.Prefab == (Object)null)) { EnemyAI component = prefab.Prefab.GetComponent(); if (!((Object)(object)component == (Object)null) && hashSet.Contains(((object)component).GetType().Name) && !((Object)(object)prefab.Prefab.GetComponent() != (Object)null)) { prefab.Prefab.AddComponent(); num++; Plugin.Log.LogInfo((object)("Injected CreatureAudioStream on " + ((object)component).GetType().Name)); } } } Plugin.Log.LogInfo((object)$"CreatureAudioStream injection complete ({num} prefab(s))."); } } } namespace BinderDyn.model { public class CreatureProfile { public string Id { get; set; } = string.Empty; public string EnemyType { get; set; } = string.Empty; public string SoundPackFolder { get; set; } = string.Empty; public bool Enabled { get; set; } = true; public List TriggerOnVanillaClips { get; set; } = new List(); public bool TriggersOnAnyClip => TriggerOnVanillaClips.Exists((string clip) => clip == "*"); public bool ShouldTriggerForClip(string? clipName) { if (string.IsNullOrEmpty(clipName)) { return false; } if (TriggersOnAnyClip) { return true; } return TriggerOnVanillaClips.Contains(clipName); } } public class CreatureProfilesFile { public List Profiles { get; set; } = new List(); } } namespace BinderDyn.config { public static class ModConfig { private static readonly Dictionary> ProfileToggles = new Dictionary>(); public static ConfigEntry PlayAlongsideVanilla { get; private set; } = null; public static void Bind(ConfigFile config, IReadOnlyList profiles) { PlayAlongsideVanilla = config.Bind("General", "PlayAlongsideVanilla", true, "When true, vanilla creature sounds play alongside custom audio. When false, vanilla sounds are suppressed for triggered clips."); ProfileToggles.Clear(); foreach (CreatureProfile profile in profiles) { ProfileToggles[profile.Id] = config.Bind("Creatures", "Enable_" + profile.Id, profile.Enabled, "Enable custom sounds for " + profile.EnemyType + " (" + profile.Id + ")."); } } public static bool IsProfileEnabled(CreatureProfile profile) { if (ProfileToggles.TryGetValue(profile.Id, out var value)) { return value.Value; } return profile.Enabled; } } } namespace BinderDyn.audio { public sealed class AudioReceiver : IDisposable { private readonly AudioSource _audioSource; private readonly int _totalSamples; private readonly CancellationToken _cancellationToken; private readonly AudioClip _clip; private readonly object _bufferLock = new object(); private int _receivedSamples; private int _bufferedMs; private bool _isPlaying; private bool _disposed; public bool HasStartedPlayback => _isPlaying; public float ClipDurationSeconds => (float)_totalSamples / 48000f; public AudioReceiver(AudioSource audioSource, int totalSamples, CancellationToken cancellationToken) { _audioSource = audioSource; _totalSamples = totalSamples; _cancellationToken = cancellationToken; _clip = AudioClip.Create($"GermanBrainrot_{Guid.NewGuid():N}", Mathf.Max(totalSamples, 960), 1, 48000, false); _audioSource.clip = _clip; } public void ReceivePacket(OpusPacket packet) { if (!_disposed && packet.Samples != null && packet.SampleCount != 0) { lock (_bufferLock) { _clip.SetData(packet.Samples, packet.SampleIndex); _receivedSamples = Math.Max(_receivedSamples, packet.SampleIndex + packet.SampleCount); _bufferedMs += 20; } TryStartPlayback(); } } private void TryStartPlayback() { if (!_isPlaying && !_disposed) { bool flag = _receivedSamples >= _totalSamples; if (_bufferedMs >= 1000 || flag) { _isPlaying = true; _audioSource.Play(); } } } public IEnumerator WaitForPlaybackComplete() { float waited = 0f; while (!_isPlaying && !_disposed && waited < 2f) { waited += Time.deltaTime; yield return null; } if (!_disposed && _isPlaying) { while (_audioSource.isPlaying && !_disposed) { yield return null; } } } public void Dispose() { if (!_disposed) { _disposed = true; if ((Object)(object)_audioSource != (Object)null && _audioSource.isPlaying) { _audioSource.Stop(); } if ((Object)(object)_clip != (Object)null) { Object.Destroy((Object)(object)_clip); } } } } public sealed class AudioSender : IDisposable { private readonly Action _sendPacket; private readonly OpusFileReader _reader; private bool _disposed; public AudioSender(Action sendPacket, OpusFileReader reader) { _sendPacket = sendPacket; _reader = reader; } public IEnumerator SendRoutine() { Stopwatch stopwatch = Stopwatch.StartNew(); int packetIndex = 0; IReadOnlyList samples = _reader.Samples; int chunkSize = 960; while (!_disposed) { int sampleIndex = packetIndex * chunkSize; if (sampleIndex >= samples.Count) { break; } int count = Math.Min(chunkSize, samples.Count - sampleIndex); float[] packetSamples = new float[count]; for (int i = 0; i < count; i++) { packetSamples[i] = samples[sampleIndex + i]; } _sendPacket(new OpusPacket { SampleIndex = sampleIndex, SampleCount = count, Samples = packetSamples }); packetIndex++; int targetMs = packetIndex * 20; long delayMs = targetMs - stopwatch.ElapsedMilliseconds; if (delayMs > 0) { yield return (object)new WaitForSeconds((float)delayMs / 1000f); } else { yield return null; } } } public void Dispose() { if (!_disposed) { _disposed = true; _reader.Dispose(); } } } public class CreatureAudioStream : NetworkBehaviour { private const float StreamCooldownSeconds = 5f; private AudioSender? _audioSender; private AudioReceiver? _audioReceiver; private CancellationTokenSource? _streamCancellation; private Coroutine? _streamCoroutine; private Transform? _followTarget; private ulong? _allowedSenderId; private float _lastStreamStartTime = float.NegativeInfinity; public AudioSource StreamAudioSource { get; private set; } = null; public bool IsStreaming => _streamCoroutine != null; public string? LastPlayedClipPath { get; private set; } private bool HasRemoteClients => (Object)(object)((NetworkBehaviour)this).NetworkManager != (Object)null && ((NetworkBehaviour)this).NetworkManager.ConnectedClientsIds.Count > 1; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown GameObject val = new GameObject("GermanBrainrotAudio"); val.transform.SetParent(((Component)this).transform, false); StreamAudioSource = val.AddComponent(); StreamAudioSource.spatialBlend = 1f; StreamAudioSource.minDistance = 1f; StreamAudioSource.maxDistance = 25f; StreamAudioSource.rolloffMode = (AudioRolloffMode)1; _followTarget = ((Component)this).transform; } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); NetcodeRpcInitializer.InitializeInstance((NetworkBehaviour)(object)this); if (((NetworkBehaviour)this).IsHost) { _allowedSenderId = ((NetworkBehaviour)this).NetworkManager.LocalClientId; } } private void LateUpdate() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_followTarget == (Object)null) && !((Object)(object)StreamAudioSource == (Object)null)) { ((Component)StreamAudioSource).transform.position = _followTarget.position; } } public override void OnDestroy() { StopStreaming(); ((NetworkBehaviour)this).OnDestroy(); } public void StreamOpusFromFile(string filePath) { if (!((NetworkBehaviour)this).IsSpawned) { Plugin.Log.LogWarning((object)("CreatureAudioStream not spawned; cannot stream " + filePath)); } else if (!IsStreaming && !(Time.time - _lastStreamStartTime < 5f)) { ulong localClientId = ((NetworkBehaviour)this).NetworkManager.LocalClientId; if (_allowedSenderId.HasValue && localClientId != _allowedSenderId.Value) { Plugin.Log.LogWarning((object)$"Client {localClientId} is not allowed to stream audio on {((Object)((Component)this).gameObject).name}"); return; } _lastStreamStartTime = Time.time; LastPlayedClipPath = filePath; _streamCoroutine = ((MonoBehaviour)this).StartCoroutine(StreamOpusFromFileRoutine(filePath)); } } private IEnumerator StreamOpusFromFileRoutine(string filePath) { CleanupStreamResources(); _streamCancellation = new CancellationTokenSource(); OpusFileReader reader = null; Exception loadError = null; bool loadComplete = false; Task.Run(delegate { try { reader = OpusFileReader.FromFile(filePath); } catch (Exception ex) { loadError = ex; } finally { loadComplete = true; } }); while (!loadComplete) { yield return null; } if (loadError != null) { Plugin.Log.LogError((object)("Failed to read audio file " + filePath + ": " + loadError.Message)); CleanupStreamResources(); _streamCoroutine = null; yield break; } if (reader == null || reader.TotalSamples == 0) { Plugin.Log.LogWarning((object)("Audio file has no samples: " + filePath)); reader?.Dispose(); CleanupStreamResources(); _streamCoroutine = null; yield break; } Exception streamError = null; if (((NetworkBehaviour)this).IsHost) { InitializeAudioReceiver(reader.TotalSamples); if (HasRemoteClients) { InitializeAudioReceiverClientRpc(reader.TotalSamples); } _audioSender = new AudioSender(delegate(OpusPacket packet) { _audioReceiver?.ReceivePacket(packet); if (HasRemoteClients) { SendPacketClientRpc(packet); } }, reader); yield return RunSendRoutine(delegate(Exception error) { streamError = error; }); } else { ServerRpcParams serverRpcParams = default(ServerRpcParams); InitializeAudioReceiverServerRpc(reader.TotalSamples, serverRpcParams); _audioSender = new AudioSender(delegate(OpusPacket packet) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) SendPacketServerRpc(packet, serverRpcParams); Array.Clear(packet.Samples, 0, packet.SampleCount); }, reader); yield return RunSendRoutine(delegate(Exception error) { streamError = error; }); } if (streamError != null) { Plugin.Log.LogError((object)$"Error streaming audio: {streamError}"); } if (_audioReceiver != null) { yield return _audioReceiver.WaitForPlaybackComplete(); } CleanupStreamResources(); _streamCoroutine = null; } private IEnumerator RunSendRoutine(Action onError) { if (_audioSender == null) { yield break; } IEnumerator sendRoutine = _audioSender.SendRoutine(); while (true) { object current; try { if (!sendRoutine.MoveNext()) { break; } current = sendRoutine.Current; } catch (Exception ex) { Exception ex2 = ex; onError(ex2); break; } yield return current; } } private void InitializeAudioReceiver(int totalSamples) { _audioReceiver?.Dispose(); _audioReceiver = new AudioReceiver(StreamAudioSource, totalSamples, _streamCancellation.Token); } [ClientRpc] private void InitializeAudioReceiverClientRpc(int totalSamples) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3574556932u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, totalSamples); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3574556932u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && !((NetworkBehaviour)this).IsHost) { if (_streamCancellation == null) { _streamCancellation = new CancellationTokenSource(); } InitializeAudioReceiver(totalSamples); } } [ServerRpc(RequireOwnership = false)] private void InitializeAudioReceiverServerRpc(int totalSamples, ServerRpcParams serverRpcParams) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(3882811510u, serverRpcParams, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, totalSamples); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 3882811510u, serverRpcParams, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && IsValidSender(serverRpcParams.Receive.SenderClientId)) { InitializeAudioReceiver(totalSamples); InitializeAudioReceiverClientRpc(totalSamples); } } } [ClientRpc] private void SendPacketClientRpc(OpusPacket packet) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3121956404u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe(ref packet, default(ForNetworkSerializable)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3121956404u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && !((NetworkBehaviour)this).IsHost) { _audioReceiver?.ReceivePacket(packet); } } } [ServerRpc(RequireOwnership = false)] private void SendPacketServerRpc(OpusPacket packet, ServerRpcParams serverRpcParams) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(1554328546u, serverRpcParams, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe(ref packet, default(ForNetworkSerializable)); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 1554328546u, serverRpcParams, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && IsValidSender(serverRpcParams.Receive.SenderClientId)) { _audioReceiver?.ReceivePacket(packet); SendPacketClientRpc(packet); } } } private bool IsValidSender(ulong senderClientId) { return ((NetworkBehaviour)this).IsHost && ((NetworkBehaviour)this).NetworkManager.ConnectedClients.ContainsKey(senderClientId) && _allowedSenderId.HasValue && senderClientId == _allowedSenderId.Value; } private void StopStreaming() { if (_streamCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_streamCoroutine); _streamCoroutine = null; } CleanupStreamResources(); } private void CleanupStreamResources() { _streamCancellation?.Cancel(); _streamCancellation?.Dispose(); _streamCancellation = null; _audioSender?.Dispose(); _audioSender = null; _audioReceiver?.Dispose(); _audioReceiver = null; } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } [RuntimeInitializeOnLoadMethod] internal static void InitializeRPCS_CreatureAudioStream() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown NetworkManager.__rpc_func_table.Add(3574556932u, new RpcReceiveHandler(__rpc_handler_3574556932)); NetworkManager.__rpc_func_table.Add(3882811510u, new RpcReceiveHandler(__rpc_handler_3882811510)); NetworkManager.__rpc_func_table.Add(3121956404u, new RpcReceiveHandler(__rpc_handler_3121956404)); NetworkManager.__rpc_func_table.Add(1554328546u, new RpcReceiveHandler(__rpc_handler_1554328546)); } private static void __rpc_handler_3574556932(NetworkBehaviour? target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int totalSamples = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref totalSamples); target.__rpc_exec_stage = (__RpcExecStage)2; ((CreatureAudioStream)(object)target).InitializeAudioReceiverClientRpc(totalSamples); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_3882811510(NetworkBehaviour? target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int totalSamples = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref totalSamples); ServerRpcParams server = rpcParams.Server; target.__rpc_exec_stage = (__RpcExecStage)1; ((CreatureAudioStream)(object)target).InitializeAudioReceiverServerRpc(totalSamples, server); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_3121956404(NetworkBehaviour? target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { OpusPacket packet = default(OpusPacket); ((FastBufferReader)(ref reader)).ReadValueSafe(ref packet, default(ForNetworkSerializable)); target.__rpc_exec_stage = (__RpcExecStage)2; ((CreatureAudioStream)(object)target).SendPacketClientRpc(packet); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_1554328546(NetworkBehaviour? target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { OpusPacket packet = default(OpusPacket); ((FastBufferReader)(ref reader)).ReadValueSafe(ref packet, default(ForNetworkSerializable)); ServerRpcParams server = rpcParams.Server; target.__rpc_exec_stage = (__RpcExecStage)1; ((CreatureAudioStream)(object)target).SendPacketServerRpc(packet, server); target.__rpc_exec_stage = (__RpcExecStage)0; } } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string? __getTypeName() { return "CreatureAudioStream"; } } public static class OpusConstants { public const int SampleRate = 48000; public const int Channels = 1; public const int FrameSizeMs = 20; public const int SamplesPerPacket = 960; public const int MinimumBufferedAudioMs = 1000; } public sealed class OpusFileReader : IDisposable { private readonly List _samples = new List(); private bool _disposed; public IReadOnlyList Samples => _samples; public int TotalSamples => _samples.Count; public static OpusFileReader FromFile(string filePath) { OpusFileReader opusFileReader = new OpusFileReader(); opusFileReader.Load(filePath); return opusFileReader; } private void Load(string filePath) { string extension = Path.GetExtension(filePath); if (extension.Equals(".wav", StringComparison.OrdinalIgnoreCase)) { LoadWav(filePath); } else { LoadOpus(filePath); } } private void LoadOpus(string filePath) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown using FileStream fileStream = File.OpenRead(filePath); IOpusDecoder val = OpusCodecFactory.CreateDecoder(48000, 1, (TextWriter)null); OpusOggReadStream val2 = new OpusOggReadStream(val, (Stream)fileStream); while (val2.HasNextPacket) { short[] array = val2.DecodeNextPacket(); if (array != null && array.Length != 0) { short[] array2 = array; foreach (short num in array2) { _samples.Add((float)num / 32768f); } } } } private void LoadWav(string filePath) { using FileStream input = File.OpenRead(filePath); using BinaryReader binaryReader = new BinaryReader(input); string text = new string(binaryReader.ReadChars(4)); if (text != "RIFF") { throw new InvalidDataException("Not a WAV file: " + filePath); } binaryReader.ReadInt32(); string text2 = new string(binaryReader.ReadChars(4)); if (text2 != "WAVE") { throw new InvalidDataException("Not a WAV file: " + filePath); } short channels = 1; int sampleRate = 48000; short bitsPerSample = 16; long offset = 0L; int num = 0; while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length) { string text3 = new string(binaryReader.ReadChars(4)); int num2 = binaryReader.ReadInt32(); string text4 = text3; string text5 = text4; if (!(text5 == "fmt ")) { if (text5 == "data") { offset = binaryReader.BaseStream.Position; num = num2; binaryReader.BaseStream.Seek(num2, SeekOrigin.Current); } else { binaryReader.BaseStream.Seek(num2, SeekOrigin.Current); } continue; } binaryReader.ReadInt16(); channels = binaryReader.ReadInt16(); sampleRate = binaryReader.ReadInt32(); binaryReader.ReadInt32(); binaryReader.ReadInt16(); bitsPerSample = binaryReader.ReadInt16(); if (num2 > 16) { binaryReader.BaseStream.Seek(num2 - 16, SeekOrigin.Current); } } if (num == 0) { throw new InvalidDataException("WAV file has no data chunk: " + filePath); } binaryReader.BaseStream.Seek(offset, SeekOrigin.Begin); byte[] bytes = binaryReader.ReadBytes(num); AppendPcm(bytes, channels, bitsPerSample, sampleRate); } private void AppendPcm(byte[] bytes, short channels, short bitsPerSample, int sampleRate) { if (bitsPerSample != 16) { throw new NotSupportedException("Only 16-bit PCM WAV files are supported."); } int num = bytes.Length / (bitsPerSample / 8); for (int i = 0; i < num; i += channels) { short num2 = BitConverter.ToInt16(bytes, i * 2); _samples.Add((float)num2 / 32768f); } if (sampleRate != 48000 && _samples.Count > 0) { ResampleToTargetRate(sampleRate); } } private void ResampleToTargetRate(int sourceRate) { if (sourceRate == 48000) { return; } List list = new List(); double num = (double)sourceRate / 48000.0; int num2 = (int)((double)_samples.Count / num); for (int i = 0; i < num2; i++) { int num3 = (int)((double)i * num); if (num3 >= _samples.Count) { num3 = _samples.Count - 1; } list.Add(_samples[num3]); } _samples.Clear(); _samples.AddRange(list); } public void Dispose() { if (!_disposed) { _disposed = true; _samples.Clear(); } } } public struct OpusPacket : INetworkSerializable, IEquatable { public int SampleIndex; public int SampleCount; public float[] Samples; public unsafe void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (!serializer.IsReader && Samples != null) { SampleCount = Samples.Length; } ((BufferSerializer*)(&serializer))->SerializeValue(ref SampleIndex, default(ForPrimitives)); ((BufferSerializer*)(&serializer))->SerializeValue(ref SampleCount, default(ForPrimitives)); if (serializer.IsReader) { float[] samples = Samples; Samples = ((samples != null && samples.Length > 0) ? Samples : new float[SampleCount]); } else if (Samples == null) { Samples = Array.Empty(); SampleCount = 0; } for (int i = 0; i < SampleCount; i++) { ((BufferSerializer*)(&serializer))->SerializeValue(ref Samples[i], default(ForPrimitives)); } } public bool Equals(OpusPacket other) { if (SampleIndex != other.SampleIndex || SampleCount != other.SampleCount) { return false; } for (int i = 0; i < SampleCount; i++) { if (Math.Abs(Samples[i] - other.Samples[i]) > 0.0001f) { return false; } } return true; } public override bool Equals(object? obj) { return obj is OpusPacket other && Equals(other); } public override int GetHashCode() { return HashCode.Combine(SampleIndex, SampleCount); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace GermanBrainrot.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }