using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dissonance; using Dissonance.Audio.Capture; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using NAudio.Wave; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CapsCrew.Splendiphius")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CapsCrew.Splendiphius")] [assembly: AssemblyTitle("CapsCrew.Splendiphius")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] 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 CapsCrew.KylesMom { internal sealed class KyleMomVisual : MonoBehaviour { private const string PlaneName = "KylesMomPlane"; private FlowermanAI? _bracken; private GameObject? _plane; private MeshRenderer? _planeRenderer; private bool _scanRenamed; internal static void Ensure(FlowermanAI bracken) { if (!((Object)(object)bracken == (Object)null) && Plugin.EnableSwap.Value && !((Object)(object)Plugin.FaceTexture == (Object)null)) { KyleMomVisual kyleMomVisual = ((Component)bracken).GetComponent(); if ((Object)(object)kyleMomVisual == (Object)null) { kyleMomVisual = ((Component)bracken).gameObject.AddComponent(); } kyleMomVisual.Bind(bracken); } } private void Bind(FlowermanAI bracken) { _bracken = bracken; if ((Object)(object)_plane == (Object)null) { CreatePlane(bracken); } RenameScanOnce(bracken); ApplyVisibility(); } private void LateUpdate() { if (!((Object)(object)_bracken == (Object)null) && !((Object)(object)_plane == (Object)null)) { ApplyVisibility(); FaceLocalPlayer(); } } private void OnDestroy() { if ((Object)(object)_plane != (Object)null) { Object.Destroy((Object)(object)_plane); } } private void CreatePlane(FlowermanAI bracken) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) Texture2D faceTexture = Plugin.FaceTexture; if (!((Object)(object)faceTexture == (Object)null)) { GameObject val = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val).name = "KylesMomPlane"; val.layer = ((Component)bracken).gameObject.layer; Collider component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } float num = Mathf.Max(0.4f, Plugin.PlaneHeight.Value); float num2 = ((((Texture)faceTexture).height > 0) ? ((float)((Texture)faceTexture).width / (float)((Texture)faceTexture).height) : 0.63f); float num3 = num * num2; float num4 = num * 0.5f + Plugin.GroundOffset.Value; val.transform.SetParent(((Component)bracken).transform, false); val.transform.localPosition = new Vector3(0f, num4, 0f); val.transform.localRotation = Quaternion.identity; val.transform.localScale = new Vector3(num3, num, 1f); MeshRenderer component2 = val.GetComponent(); Material sharedMaterial = MakeMaterial(faceTexture); ((Renderer)component2).sharedMaterial = sharedMaterial; ((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component2).receiveShadows = false; ((Renderer)component2).lightProbeUsage = (LightProbeUsage)0; ((Renderer)component2).reflectionProbeUsage = (ReflectionProbeUsage)0; _plane = val; _planeRenderer = component2; Plugin.Log.LogInfo((object)$"Pinned plane at local y={num4:0.00} size={num3:0.00}x{num:0.00}"); } } private static Material MakeMaterial(Texture2D texture) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown Material val = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent") ?? Shader.Find("Unlit/Texture") ?? Shader.Find("UI/Default") ?? Shader.Find("Standard")) { name = "KylesMomSprite", mainTexture = (Texture)(object)texture, color = Color.white, hideFlags = (HideFlags)61 }; if (val.HasProperty("_MainTex")) { val.SetTexture("_MainTex", (Texture)(object)texture); } if (val.HasProperty("_Cull")) { val.SetInt("_Cull", 0); } val.renderQueue = 3000; return val; } private void ApplyVisibility() { if (!((Object)(object)_bracken == (Object)null) && !((Object)(object)_planeRenderer == (Object)null)) { bool flag = !((EnemyAI)_bracken).isEnemyDead && ((Component)_bracken).gameObject.activeInHierarchy; bool saw = false; bool anyEnabled = false; Renderer[] skinnedMeshRenderers = (Renderer[])(object)((EnemyAI)_bracken).skinnedMeshRenderers; NoteEnabled(skinnedMeshRenderers, ref saw, ref anyEnabled); skinnedMeshRenderers = (Renderer[])(object)((EnemyAI)_bracken).meshRenderers; NoteEnabled(skinnedMeshRenderers, ref saw, ref anyEnabled); if (saw) { flag = flag && anyEnabled; } if ((Object)(object)_bracken.animationContainer != (Object)null && !((Component)_bracken.animationContainer).gameObject.activeInHierarchy) { flag = false; } SuppressAllGameRenderers(); ((Renderer)_planeRenderer).enabled = flag; } } private static void NoteEnabled(Renderer[]? renderers, ref bool saw, ref bool anyEnabled) { if (renderers == null) { return; } foreach (Renderer val in renderers) { if (!((Object)(object)val == (Object)null)) { saw = true; if (val.enabled) { anyEnabled = true; } } } } private void SuppressAllGameRenderers() { if ((Object)(object)_bracken == (Object)null) { return; } Renderer[] skinnedMeshRenderers = (Renderer[])(object)((EnemyAI)_bracken).skinnedMeshRenderers; HideArray(skinnedMeshRenderers); skinnedMeshRenderers = (Renderer[])(object)((EnemyAI)_bracken).meshRenderers; HideArray(skinnedMeshRenderers); Renderer[] componentsInChildren = ((Component)_bracken).GetComponentsInChildren(true); foreach (Renderer renderer in componentsInChildren) { if (!IsOurRenderer(renderer)) { HideRenderer(renderer); } } } private static void HideArray(Renderer[]? renderers) { if (renderers == null) { return; } for (int i = 0; i < renderers.Length; i++) { if ((Object)(object)renderers[i] != (Object)null) { HideRenderer(renderers[i]); } } } private bool IsOurRenderer(Renderer renderer) { if ((Object)(object)_plane == (Object)null || (Object)(object)renderer == (Object)null) { return false; } if (!((Object)(object)((Component)renderer).gameObject == (Object)(object)_plane)) { return ((Component)renderer).transform.IsChildOf(_plane.transform); } return true; } private static void HideRenderer(Renderer renderer) { renderer.forceRenderingOff = true; renderer.shadowCastingMode = (ShadowCastingMode)0; renderer.receiveShadows = false; } private void FaceLocalPlayer() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.FacePlayer.Value || (Object)(object)_plane == (Object)null) { return; } Camera val = LocalCamera(); if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)val).transform.position - _plane.transform.position; val2.y = 0f; if (!(((Vector3)(ref val2)).sqrMagnitude < 0.0001f)) { _plane.transform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up); } } } private static Camera? LocalCamera() { GameNetworkManager instance = GameNetworkManager.Instance; PlayerControllerB val = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null); if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) { return val.gameplayCamera; } return Camera.main; } private void RenameScanOnce(FlowermanAI bracken) { if (_scanRenamed) { return; } string value = Plugin.ScanName.Value; if (string.IsNullOrWhiteSpace(value)) { _scanRenamed = true; return; } ScanNodeProperties componentInChildren = ((Component)bracken).GetComponentInChildren(true); if (!((Object)(object)componentInChildren == (Object)null)) { componentInChildren.headerText = value.Trim(); _scanRenamed = true; } } } [BepInPlugin("capscrew.splendiphius", "Splendiphius", "2.2.9")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "capscrew.splendiphius"; public const string PluginName = "Splendiphius"; public const string PluginVersion = "2.2.9"; public const string ImageFileName = "content.png"; internal static Plugin Instance; internal static ManualLogSource Log; internal static Texture2D? FaceTexture; internal static ConfigEntry EnableSwap; internal static ConfigEntry PlaneHeight; internal static ConfigEntry GroundOffset; internal static ConfigEntry FacePlayer; internal static ConfigEntry ScanName; internal static ConfigEntry ExtraLayer; internal static ConfigEntry ExtraLayerWeatherGate; internal static ConfigEntry ExtraLayerAfterHour; internal static ConfigEntry ExtraLayerChanceMin; internal static ConfigEntry ExtraLayerChanceMax; internal static ConfigEntry ExtraLayerIntervalMin; internal static ConfigEntry ExtraLayerIntervalMax; internal static ConfigEntry ExtraLayerTestMode; internal static ConfigEntry ExtraLayerDelay; internal static ConfigEntry ExtraLayerPitch; internal static ConfigEntry ExtraLayerVolume; private void Awake() { //IL_0265: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; EnableSwap = ((BaseUnityPlugin)this).Config.Bind("General", "EnableSwap", true, "On or off."); PlaneHeight = ((BaseUnityPlugin)this).Config.Bind("General", "PlaneHeight", 2.85f, "Height in meters."); GroundOffset = ((BaseUnityPlugin)this).Config.Bind("General", "GroundOffset", 0.02f, "Lift off the root."); FacePlayer = ((BaseUnityPlugin)this).Config.Bind("General", "FacePlayer", true, "Yaw toward the local player."); ScanName = ((BaseUnityPlugin)this).Config.Bind("General", "ScanName", "Kyle's Mom", "Scanner label. Empty keeps the original."); ExtraLayer = ((BaseUnityPlugin)this).Config.Bind("Layer", "Enable", true, "On or off."); ExtraLayerWeatherGate = ((BaseUnityPlugin)this).Config.Bind("Layer", "WeatherGate", true, "Only while the current world allows it."); ExtraLayerAfterHour = ((BaseUnityPlugin)this).Config.Bind("Layer", "AfterHour", 12, "HUD clock hour (24h). 12 = noon. Ignored in test mode."); ExtraLayerChanceMin = ((BaseUnityPlugin)this).Config.Bind("Layer", "ChanceMin", 0.1f, "Low end of the per-roll chance."); ExtraLayerChanceMax = ((BaseUnityPlugin)this).Config.Bind("Layer", "ChanceMax", 0.2f, "High end of the per-roll chance."); ExtraLayerIntervalMin = ((BaseUnityPlugin)this).Config.Bind("Layer", "IntervalMin", 60f, "Seconds between rolls, low end."); ExtraLayerIntervalMax = ((BaseUnityPlugin)this).Config.Bind("Layer", "IntervalMax", 120f, "Seconds between rolls, high end."); ExtraLayerTestMode = ((BaseUnityPlugin)this).Config.Bind("Layer", "TestMode", false, "Skip fog/noon only. Same 60-120s rolls as live. Off in space. Also on if layer.test sits next to the DLL."); ExtraLayerDelay = ((BaseUnityPlugin)this).Config.Bind("Layer", "Delay", 0.72f, "Seconds."); ExtraLayerPitch = ((BaseUnityPlugin)this).Config.Bind("Layer", "Pitch", 0.91f, "Playback pitch."); ExtraLayerVolume = ((BaseUnityPlugin)this).Config.Bind("Layer", "Volume", 0.82f, "Playback volume."); FaceTexture = LoadFaceTexture(); if ((Object)(object)FaceTexture == (Object)null) { Log.LogError((object)"content.png failed to load."); } new Harmony("capscrew.splendiphius").PatchAll(); Log.LogInfo((object)("Splendiphius v2.2.9 loaded from " + ((BaseUnityPlugin)this).Info.Location)); VoiceBoxLog.Note("LOAD", string.Format("v{0} test={1} interval={2:0}-{3:0}s chance={4:0.00}-{5:0.00}", "2.2.9", IsTestMode(), ExtraLayerIntervalMin.Value, ExtraLayerIntervalMax.Value, ExtraLayerChanceMin.Value, ExtraLayerChanceMax.Value)); } internal static bool IsTestMode() { if (ExtraLayerTestMode != null && ExtraLayerTestMode.Value) { return true; } try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)Instance).Info.Location); if (!string.IsNullOrWhiteSpace(directoryName) && File.Exists(Path.Combine(directoryName, "layer.test"))) { return true; } } catch { } return false; } internal static Texture2D? LoadFaceTexture() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)Instance).Info.Location); if (string.IsNullOrWhiteSpace(directoryName)) { return null; } string text = Path.Combine(directoryName, "content.png"); if (!File.Exists(text)) { Log.LogError((object)("Missing image next to the plugin DLL: " + text)); return null; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array)) { Log.LogError((object)("Unity could not decode " + text)); Object.Destroy((Object)(object)val); return null; } ((Object)val).name = "content"; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)0; ((Texture)val).anisoLevel = 0; ((Object)val).hideFlags = (HideFlags)61; Log.LogInfo((object)string.Format("Loaded {0} {1}x{2}", "content.png", ((Texture)val).width, ((Texture)val).height)); return val; } } internal static class VoiceBox { private static bool _loggedTickError; internal static float ChanceMin => Plugin.ExtraLayerChanceMin.Value; internal static float ChanceMax => Plugin.ExtraLayerChanceMax.Value; internal static float IntervalMin => Plugin.ExtraLayerIntervalMin.Value; internal static float IntervalMax => Plugin.ExtraLayerIntervalMax.Value; internal static bool IsTestMode() { return Plugin.IsTestMode(); } internal static bool IsOnMoon() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && !instance.inShipPhase && instance.shipHasLanded) { return !instance.shipIsLeaving; } return false; } internal static bool WorldAllowsLayer() { string text = GateStatus(); if (text == "test-ok" || text == "live-ok") { return true; } return false; } internal static string GateStatus() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 if (Plugin.ExtraLayer == null || !Plugin.ExtraLayer.Value) { return "layer-off"; } if (!IsOnMoon()) { return "not-on-moon"; } if (IsTestMode()) { return "test-ok"; } if (Plugin.ExtraLayerWeatherGate.Value) { TimeOfDay instance = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null || (int)instance.currentLevelWeather != 3) { return "not-foggy"; } } if (!IsAtOrAfterNoon()) { return "before-noon"; } return "live-ok"; } internal static bool IsAtOrAfterNoon() { TimeOfDay instance = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null) { return false; } int clockHour = GetClockHour24(instance); int num = Mathf.Clamp(Plugin.ExtraLayerAfterHour.Value, 0, 23); if (clockHour == 0) { return num <= 12; } return clockHour >= num; } internal static int GetClockHour24(TimeOfDay time) { int num = Mathf.Max(1, time.numberOfHours); int num2 = ((int)(time.normalizedTimeOfDay * (60f * (float)num)) + 360) / 60; if (num2 < 24) { return num2; } return 0; } internal static bool IsLocalPlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return true; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.localPlayerController == (Object)(object)player) { return true; } if (((NetworkBehaviour)player).IsOwner) { return player.isPlayerControlled; } return false; } internal static void Tick() { try { VoiceBoxDirector.Tick(); } catch (Exception ex) { if (!_loggedTickError) { _loggedTickError = true; VoiceBoxLog.Note("SKIP", "tick-error " + ex.Message); ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"VoiceBox tick: {ex}"); } } } } } internal sealed class VoiceBoxCache : MonoBehaviour, IMicrophoneSubscriber { private const int MaxClips = 24; private const int NetworkRate = 16000; private const float MinSeconds = 1f; private const float MaxSeconds = 10f; private const float EndSilence = 0.7f; private const float SpeakStart = 0.012f; private const float SpeakHold = 0.006f; private static GameObject? _host; private readonly List _clips = new List(); private readonly object _gate = new object(); private readonly List _current = new List(); private DissonanceComms? _comms; private bool _subscribed; private volatile bool _pendingReady; private float _silence; private int _micRate = 16000; private int _lastBucket = -1; internal static VoiceBoxCache? Instance { get; private set; } internal int ClipCount { get { lock (_gate) { return _clips.Count; } } } internal bool IsSubscribed => _subscribed; internal bool HasSnippets { get { lock (_gate) { return _clips.Count > 0; } } } internal static void Ensure() { if (Object.op_Implicit((Object)(object)Instance)) { return; } try { GameObject val = ResolveHost(); if (!((Object)(object)val == (Object)null)) { Instance = val.GetComponent() ?? val.AddComponent(); Instance.ImportMimicFolder(); VoiceBoxLog.Note("CACHE", "host-ready"); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("VoiceBox cache start failed: " + ex.Message)); } } } private static GameObject? ResolveHost() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)_host)) { return _host; } Plugin instance = Plugin.Instance; if (Object.op_Implicit((Object)(object)instance)) { _host = ((Component)instance).gameObject; return _host; } _host = new GameObject("CapsCrew.SLayer.Cache"); Object.DontDestroyOnLoad((Object)(object)_host); return _host; } internal bool TryPick(out float[] samples, out int sampleRate) { sampleRate = 16000; lock (_gate) { if (_clips.Count == 0) { samples = Array.Empty(); return false; } int index = PickVariedIndex(); samples = _clips[index]; _lastBucket = Bucket(samples.Length); return samples.Length != 0; } } private int PickVariedIndex() { List[] array = new List[3] { new List(), new List(), new List() }; for (int i = 0; i < _clips.Count; i++) { array[Bucket(_clips[i].Length)].Add(i); } List list = new List(); for (int j = 0; j < 3; j++) { if (j != _lastBucket && array[j].Count > 0) { list.Add(j); } } for (int k = 0; k < 3; k++) { if (!list.Contains(k) && array[k].Count > 0) { list.Add(k); } } if (list.Count == 0) { return 0; } int num = list[0]; if (list.Count > 1 && Random.value < 0.65f) { num = list[Random.Range(0, list.Count)]; } List list2 = array[num]; return list2[Random.Range(0, list2.Count)]; } private static int Bucket(int sampleCount) { float num = (float)sampleCount / 16000f; if (num < 3f) { return 0; } if (!(num < 6f)) { return 2; } return 1; } internal void TrySubscribe() { if (_subscribed) { return; } StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null)) { ref DissonanceComms? comms = ref _comms; object? obj = AccessTools.Field(typeof(StartOfRound), "voiceChatModule")?.GetValue(instance); comms = (DissonanceComms?)((obj is DissonanceComms) ? obj : null); if ((Object)(object)_comms == (Object)null) { _comms = Object.FindObjectOfType(); } if (!((Object)(object)_comms == (Object)null)) { _comms.SubscribeToRecordedAudio((IMicrophoneSubscriber)(object)this); _subscribed = true; VoiceBoxLog.Note("MIC", "subscribed"); } } } internal void ImportMimicFolder() { try { string fullPath = Path.GetFullPath(Path.Combine(Application.dataPath, "..", "Mirage")); if (!Directory.Exists(fullPath)) { VoiceBoxLog.Note("CACHE", "disk-folder-missing"); return; } string[] files = Directory.GetFiles(fullPath, "*.wav", SearchOption.AllDirectories); string[] files2 = Directory.GetFiles(fullPath, "*.opus", SearchOption.AllDirectories); int num = 0; string[] array = files; for (int i = 0; i < array.Length; i++) { if (TryReadWavMono(array[i], out float[] samples) && samples.Length > 16000) { PushClip(samples); num++; } } VoiceBoxLog.Note("CACHE", $"disk wav={files.Length} imported={num} opus={files2.Length} (opus-not-read)"); } catch (Exception ex) { VoiceBoxLog.Note("CACHE", "disk-error " + ex.Message); } } internal void FlushReady() { if (_pendingReady) { _pendingReady = false; VoiceBoxNetwork.NotifyReady(); } } public void ReceiveMicrophoneData(ArraySegment buffer, WaveFormat format) { try { ReceiveMicrophoneDataInner(buffer, format); } catch { } } private void ReceiveMicrophoneDataInner(ArraySegment buffer, WaveFormat format) { if (buffer.Array == null || buffer.Count < 8) { return; } _micRate = ((format.SampleRate > 0) ? format.SampleRate : 16000); float num = 0f; int num2 = buffer.Offset + buffer.Count; for (int i = buffer.Offset; i < num2; i++) { float num3 = buffer.Array[i]; num += num3 * num3; } num = Mathf.Sqrt(num / (float)buffer.Count); bool flag = _current.Count > 0; bool num4 = num > (flag ? 0.006f : 0.012f); int num5 = (int)((float)_micRate * 10f); if (num4) { _silence = 0f; for (int j = buffer.Offset; j < num2; j++) { if (_current.Count >= num5) { break; } _current.Add(buffer.Array[j]); } if (_current.Count >= num5) { FlushCurrent(); } } else if (_current.Count > 0) { _silence += (float)buffer.Count / (float)_micRate; if (_silence >= 0.7f) { FlushCurrent(); } } } public void Reset() { _current.Clear(); _silence = 0f; } private void FlushCurrent() { if ((float)_current.Count < (float)_micRate * 1f) { _current.Clear(); _silence = 0f; return; } float[] source = _current.ToArray(); _current.Clear(); _silence = 0f; PushClip(Downsample(source, _micRate)); } private void PushClip(float[] samples) { if ((float)samples.Length < 16000f) { return; } bool flag = false; lock (_gate) { flag = _clips.Count == 0; if (_clips.Count >= 24) { _clips.RemoveAt(0); } _clips.Add(samples); } VoiceBoxLog.Note("CLIP", $"keep secs={(float)samples.Length / 16000f:0.00} n={ClipCount}"); if (flag) { _pendingReady = true; } } internal static float[] Resample(float[] source, int sourceRate, int destRate) { if (sourceRate <= 0 || destRate <= 0 || source.Length == 0) { return Array.Empty(); } if (sourceRate == destRate) { return source; } float num = (float)sourceRate / (float)destRate; int num2 = Mathf.Max(1, Mathf.FloorToInt((float)source.Length / num)); float[] array = new float[num2]; for (int i = 0; i < num2; i++) { int num3 = Mathf.Clamp(Mathf.FloorToInt((float)i * num), 0, source.Length - 1); array[i] = source[num3]; } return array; } private static float[] Downsample(float[] source, int sourceRate) { return Resample(source, sourceRate, 16000); } private static bool TryReadWavMono(string path, out float[] samples) { samples = Array.Empty(); byte[] array = File.ReadAllBytes(path); if (array.Length < 44) { return false; } short num = BitConverter.ToInt16(array, 22); int sourceRate = BitConverter.ToInt32(array, 24); short num2 = BitConverter.ToInt16(array, 34); int i; int num3; for (i = 12; i + 8 < array.Length && (array[i] != 100 || array[i + 1] != 97); i += 8 + num3) { num3 = BitConverter.ToInt32(array, i + 4); } if (i + 8 >= array.Length) { return false; } int num4 = BitConverter.ToInt32(array, i + 4); int num5 = i + 8; if (num2 != 16 || num < 1) { return false; } int num6 = num4 / (2 * num); float[] array2 = new float[num6]; for (int j = 0; j < num6; j++) { int num7 = num5 + j * 2 * num; if (num7 + 1 >= array.Length) { break; } array2[j] = (float)BitConverter.ToInt16(array, num7) / 32768f; } samples = Resample(array2, sourceRate, 16000); return samples.Length != 0; } private void OnDestroy() { if (_subscribed && (Object)(object)_comms != (Object)null) { try { _comms.UnsubscribeFromRecordedAudio((IMicrophoneSubscriber)(object)this); } catch { } } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } } internal static class VoiceBoxDirector { private static readonly HashSet ReadyClients = new HashSet(); private static float _nextRollAt; private static bool _busy; private static bool _onMoon; private static float _nextMonitorAt; private static int _lastSnippetCount = -1; private static bool _loggedClientWait; internal static float LastIntervalSeconds { get; private set; } internal static int ReadyCount => ReadyClients.Count; internal static void MarkReady(ulong clientId) { if (ReadyClients.Add(clientId)) { VoiceBoxLog.Note("READY", $"client={clientId} ready={ReadyClients.Count}"); } } internal static void StopProcess() { _busy = false; _nextRollAt = 0f; _onMoon = false; VoiceBoxNetwork.ClearSend(); VoiceBoxSpeaker.Stop(); VoiceBoxGhost.ReleaseAll(); } internal static void ClearRound() { ReadyClients.Clear(); VoiceBoxLog.Note("LEAVE", "round-clear"); StopProcess(); } internal static void Tick() { VoiceBoxCache.Ensure(); VoiceBoxNetwork.TryRegister(); VoiceBoxCache.Instance?.TrySubscribe(); VoiceBoxCache.Instance?.FlushReady(); VoiceBoxNetwork.PumpSend(); VoiceBoxSpeaker.Tick(); if (!VoiceBox.IsOnMoon()) { if (_onMoon) { VoiceBoxLog.Note("LEAVE", "left-moon"); StopProcess(); } return; } if (!_onMoon) { _onMoon = true; _nextRollAt = 0f; _nextMonitorAt = 0f; _lastSnippetCount = -1; _loggedClientWait = false; ScheduleNext(); VoiceBoxLog.Note("ENTER", $"test={VoiceBox.IsTestMode()} gate={VoiceBox.GateStatus()} host={IsHost()}"); } LogSnippetDelta(); MaybeMonitor(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { if (!_loggedClientWait) { _loggedClientWait = true; VoiceBoxLog.Note("MONITOR", $"client-wait host=false gate={VoiceBox.GateStatus()} snippets={SnippetCount()} mic={MicOn()}"); } return; } if (singleton.IsListening) { ReadyClients.Add(singleton.LocalClientId); } if (!VoiceBox.WorldAllowsLayer()) { return; } if (_nextRollAt <= 0.01f) { ScheduleNext(); } if (Time.realtimeSinceStartup < _nextRollAt || _busy) { return; } if (SnippetCount() == 0) { LastIntervalSeconds = 0.5f; _nextRollAt = Time.realtimeSinceStartup + 0.5f; VoiceBoxLog.Note("SKIP", "waiting-snippets"); return; } ScheduleNext(); float num = Random.Range(VoiceBox.ChanceMin, VoiceBox.ChanceMax); float value = Random.value; if (value > num) { VoiceBoxLog.Note("ROLL", $"result=MISS roll={value:0.00} chance={num:0.00} snippets={SnippetCount()} ready={ReadyClients.Count} gate={VoiceBox.GateStatus()}"); return; } if (!TryPickOnePlayer(out var clientId)) { VoiceBoxLog.Note("SKIP", $"reason=no-ready-player snippets={SnippetCount()} ready={ReadyClients.Count} mic={MicOn()}"); return; } VoiceBoxLog.Note("ROLL", $"result=HIT roll={value:0.00} chance={num:0.00} target={clientId} snippets={SnippetCount()} ready={ReadyClients.Count}"); _busy = true; try { VoiceBoxNetwork.HostFire(clientId); } catch (Exception ex) { VoiceBoxLog.Note("SKIP", "fire-error " + ex.Message); } finally { _busy = false; } } private static void MaybeMonitor() { if (!(Time.realtimeSinceStartup < _nextMonitorAt)) { _nextMonitorAt = Time.realtimeSinceStartup + 15f; float num = ((_nextRollAt > 0.01f) ? Mathf.Max(0f, _nextRollAt - Time.realtimeSinceStartup) : 0f); VoiceBoxLog.Note("MONITOR", $"moon=1 test={VoiceBox.IsTestMode()} host={IsHost()} gate={VoiceBox.GateStatus()} snippets={SnippetCount()} ready={ReadyClients.Count} mic={MicOn()} nextRoll={num:0}s"); } } private static void LogSnippetDelta() { int num = SnippetCount(); if (num != _lastSnippetCount) { _lastSnippetCount = num; VoiceBoxLog.Note("CLIP", $"snippets={num} mic={MicOn()}"); } } private static int SnippetCount() { if (!((Object)(object)VoiceBoxCache.Instance != (Object)null)) { return 0; } return VoiceBoxCache.Instance.ClipCount; } private static bool MicOn() { if ((Object)(object)VoiceBoxCache.Instance != (Object)null) { return VoiceBoxCache.Instance.IsSubscribed; } return false; } private static bool IsHost() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null) { return singleton.IsServer; } return false; } private static void ScheduleNext() { LastIntervalSeconds = Random.Range(VoiceBox.IntervalMin, VoiceBox.IntervalMax); _nextRollAt = Time.realtimeSinceStartup + LastIntervalSeconds; } private static bool TryPickOnePlayer(out ulong clientId) { clientId = 0uL; StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null) { return false; } List list = new List(); PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && !val.isPlayerDead && val.isPlayerControlled) { ulong ownerClientId = ((NetworkBehaviour)val).OwnerClientId; if (ReadyClients.Contains(ownerClientId) || ((Object)(object)NetworkManager.Singleton != (Object)null && ownerClientId == NetworkManager.Singleton.LocalClientId && (Object)(object)VoiceBoxCache.Instance != (Object)null && VoiceBoxCache.Instance.HasSnippets)) { list.Add(ownerClientId); } } } if (list.Count == 0) { return false; } clientId = list[Random.Range(0, list.Count)]; return true; } } internal static class VoiceBoxSpeaker { private static AudioSource? _source; private static AudioClip? _playing; private static AudioSource? _duck; private static float _duckRestore = 1f; private static float _duckUntil; internal static void Play(ulong sourceClientId, float[] samples, int sampleRate) { //IL_0197: Unknown result type (might be due to invalid IL or missing references) if (!VoiceBox.IsOnMoon()) { VoiceBoxLog.Note("SKIP", $"play-not-on-moon from={sourceClientId}"); return; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || samples == null || samples.Length < 64) { VoiceBoxLog.Note("SKIP", $"play-bad-clip from={sourceClientId} samples={((samples != null) ? samples.Length : 0)}"); return; } PlayerControllerB val = null; PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val2 in allPlayerScripts) { if ((Object)(object)val2 != (Object)null && ((NetworkBehaviour)val2).OwnerClientId == sourceClientId) { val = val2; break; } } if ((Object)(object)val == (Object)null || VoiceBox.IsLocalPlayer(val)) { VoiceBoxLog.Note("SKIP", $"play-self-or-missing from={sourceClientId}"); return; } AudioSource currentVoiceChatAudioSource = val.currentVoiceChatAudioSource; EnsureSource(val, currentVoiceChatAudioSource); if ((Object)(object)_source == (Object)null) { VoiceBoxLog.Note("SKIP", "play-no-source"); return; } if ((Object)(object)_playing != (Object)null) { Object.Destroy((Object)(object)_playing); _playing = null; } AudioClip val3 = AudioClip.Create("slayer", samples.Length, 1, sampleRate, false); val3.SetData(samples, 0); float num = Mathf.Max(0.01f, Plugin.ExtraLayerPitch.Value); float num2 = val3.length / num; Duck(currentVoiceChatAudioSource, num2); _source.Stop(); Transform val4 = (((Object)(object)currentVoiceChatAudioSource != (Object)null) ? ((Component)currentVoiceChatAudioSource).transform : ((Component)val).transform); ((Component)_source).transform.SetParent(val4, false); ((Component)_source).transform.localPosition = Vector3.zero; _source.pitch = num; _source.volume = Plugin.ExtraLayerVolume.Value; _source.clip = val3; _playing = val3; _source.Play(); VoiceBoxLog.Note("PLAY", $"from={sourceClientId} samples={samples.Length} rate={sampleRate} secs={num2:0.00} duck={(Object)(object)currentVoiceChatAudioSource != (Object)null}"); } internal static void Tick() { if (!((Object)(object)_duck == (Object)null) && !(Time.realtimeSinceStartup < _duckUntil)) { _duck.volume = _duckRestore; VoiceBoxLog.Note("DUCK", "restore"); _duck = null; if ((Object)(object)_playing != (Object)null && ((Object)(object)_source == (Object)null || !_source.isPlaying)) { Object.Destroy((Object)(object)_playing); _playing = null; } } } internal static void Stop() { if ((Object)(object)_source != (Object)null) { _source.Stop(); _source.clip = null; } if ((Object)(object)_playing != (Object)null) { Object.Destroy((Object)(object)_playing); _playing = null; } if ((Object)(object)_duck != (Object)null) { _duck.volume = _duckRestore; _duck = null; } } private static void Duck(AudioSource? voice, float seconds) { if (!((Object)(object)voice == (Object)null)) { if ((Object)(object)_duck != (Object)null && (Object)(object)_duck != (Object)(object)voice) { _duck.volume = _duckRestore; _duck = null; } if ((Object)(object)_duck != (Object)(object)voice) { _duck = voice; _duckRestore = ((voice.volume > 0.001f) ? voice.volume : 1f); voice.volume = 0f; } _duckUntil = Time.realtimeSinceStartup + Mathf.Max(0.05f, seconds); VoiceBoxLog.Note("DUCK", $"secs={seconds:0.00} was={_duckRestore:0.00}"); } } private static void EnsureSource(PlayerControllerB player, AudioSource? voice) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_source == (Object)null) { GameObject val = new GameObject("SLayerOne"); Object.DontDestroyOnLoad((Object)val); _source = val.AddComponent(); _source.playOnAwake = false; _source.loop = false; _source.dopplerLevel = 0f; _source.spatialize = false; } if ((Object)(object)voice != (Object)null) { _source.outputAudioMixerGroup = voice.outputAudioMixerGroup; _source.spatialBlend = voice.spatialBlend; _source.rolloffMode = voice.rolloffMode; _source.minDistance = voice.minDistance; _source.maxDistance = voice.maxDistance; } else { _source.spatialBlend = 1f; _source.rolloffMode = (AudioRolloffMode)1; _source.minDistance = 1.5f; _source.maxDistance = 48f; } } } internal sealed class VoiceBoxGhost : MonoBehaviour { private const string ChildName = "SLayer"; private static readonly Dictionary Active = new Dictionary(); private PlayerControllerB? _player; private AudioSource? _source; private VoiceBoxTap? _tap; private float[] _ring = Array.Empty(); private readonly object _gate = new object(); private int _write; private int _read; private bool _draining; private float _drainLeft; private float _lowpass; internal static void Ensure(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return; } int instanceID = ((Object)player).GetInstanceID(); if (Active.TryGetValue(instanceID, out VoiceBoxGhost value) && (Object)(object)value != (Object)null) { value._draining = false; value._drainLeft = 0f; value.Bind(player); return; } VoiceBoxGhost voiceBoxGhost = ((Component)player).GetComponent(); if ((Object)(object)voiceBoxGhost == (Object)null) { voiceBoxGhost = ((Component)player).gameObject.AddComponent(); } Active[instanceID] = voiceBoxGhost; voiceBoxGhost._draining = false; voiceBoxGhost.Bind(player); } internal static void BeginRelease(PlayerControllerB player) { if (!((Object)(object)player == (Object)null) && Active.TryGetValue(((Object)player).GetInstanceID(), out VoiceBoxGhost value) && !((Object)(object)value == (Object)null)) { value._draining = true; value._drainLeft = Mathf.Max(0.12f, Plugin.ExtraLayerDelay.Value); } } internal static void Release(PlayerControllerB player) { if (!((Object)(object)player == (Object)null)) { int instanceID = ((Object)player).GetInstanceID(); if (Active.TryGetValue(instanceID, out VoiceBoxGhost value) && (Object)(object)value != (Object)null) { value.Teardown(); } Active.Remove(instanceID); } } internal static void ReleaseAll() { List list = new List(Active.Values); Active.Clear(); foreach (VoiceBoxGhost item in list) { if ((Object)(object)item != (Object)null) { item.Teardown(); } } } private void Bind(PlayerControllerB player) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) _player = player; AudioSource currentVoiceChatAudioSource = player.currentVoiceChatAudioSource; if ((Object)(object)currentVoiceChatAudioSource == (Object)null) { return; } _tap = ((Component)currentVoiceChatAudioSource).GetComponent(); if ((Object)(object)_tap == (Object)null) { _tap = ((Component)currentVoiceChatAudioSource).gameObject.AddComponent(); } _tap.Ghost = this; Transform val = ((Component)player).transform.Find("SLayer"); GameObject val2; if ((Object)(object)val == (Object)null) { val2 = new GameObject("SLayer"); val2.transform.SetParent(((Component)player).transform, false); val2.transform.localPosition = new Vector3(0f, 1.6f, 0f); } else { val2 = ((Component)val).gameObject; } _source = val2.GetComponent(); if ((Object)(object)_source == (Object)null) { _source = val2.AddComponent(); } VoiceBoxPlayback voiceBoxPlayback = val2.GetComponent(); if ((Object)(object)voiceBoxPlayback == (Object)null) { voiceBoxPlayback = val2.AddComponent(); } voiceBoxPlayback.Ghost = this; _source.spatialBlend = 1f; _source.rolloffMode = (AudioRolloffMode)1; _source.minDistance = 1.5f; _source.maxDistance = 42f; _source.dopplerLevel = 0f; _source.loop = true; _source.playOnAwake = false; _source.priority = 64; _source.pitch = Plugin.ExtraLayerPitch.Value; _source.volume = Plugin.ExtraLayerVolume.Value; int outputSampleRate = AudioSettings.outputSampleRate; float num = Mathf.Clamp(Plugin.ExtraLayerDelay.Value, 0.18f, 2.4f); int num2 = Mathf.Max(1024, Mathf.CeilToInt(num * (float)outputSampleRate)); lock (_gate) { if (_ring.Length != num2) { _ring = new float[num2]; _write = 0; _read = ((num2 > 1) ? 1 : 0); } } if ((Object)(object)_source.clip == (Object)null) { _source.clip = AudioClip.Create("slayer", 1024, 1, outputSampleRate, false); } if (!_source.isPlaying) { _source.Play(); } } internal void PushSamples(float[] data, int channels) { if (data == null || data.Length == 0 || _ring.Length == 0) { return; } int num = Mathf.Max(1, channels); lock (_gate) { for (int i = 0; i < data.Length; i += num) { _ring[_write] = data[i]; _write++; if (_write >= _ring.Length) { _write = 0; } } } } internal void FillPlayback(float[] data, int channels) { if (_ring.Length == 0) { Array.Clear(data, 0, data.Length); return; } float num = 0.18f; int num2 = Mathf.Max(1, channels); lock (_gate) { for (int i = 0; i < data.Length; i++) { if (i % num2 != 0) { data[i] = 0f; continue; } float num3 = _ring[_read]; _read++; if (_read >= _ring.Length) { _read = 0; } _lowpass += num * (num3 - _lowpass); data[i] = _lowpass; } } } private void LateUpdate() { if ((Object)(object)_player == (Object)null) { Teardown(); } else if (_draining) { _drainLeft -= Time.deltaTime; if (_drainLeft <= 0f) { Release(_player); } } } private void Teardown() { if ((Object)(object)_tap != (Object)null && (Object)(object)_tap.Ghost == (Object)(object)this) { _tap.Ghost = null; } if ((Object)(object)_source != (Object)null) { VoiceBoxPlayback component = ((Component)_source).GetComponent(); if ((Object)(object)component != (Object)null) { component.Ghost = null; } _source.Stop(); } _draining = false; Object.Destroy((Object)(object)this); } private void OnDestroy() { if ((Object)(object)_player != (Object)null) { Active.Remove(((Object)_player).GetInstanceID()); } } } internal sealed class VoiceBoxTap : MonoBehaviour { internal VoiceBoxGhost? Ghost; private void OnAudioFilterRead(float[] data, int channels) { Ghost?.PushSamples(data, channels); } } internal sealed class VoiceBoxPlayback : MonoBehaviour { internal VoiceBoxGhost? Ghost; private void OnAudioFilterRead(float[] data, int channels) { if ((Object)(object)Ghost == (Object)null) { Array.Clear(data, 0, data.Length); } else { Ghost.FillPlayback(data, channels); } } } internal static class VoiceBoxLog { internal static void Note(string action, string detail) { string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); float lastIntervalSeconds = VoiceBoxDirector.LastIntervalSeconds; string text2 = ((lastIntervalSeconds > 0.01f) ? lastIntervalSeconds.ToString("0") : VoiceBox.IntervalMin.ToString("0")); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[SPLENDIPHIUS] [" + action + "] [" + text + "] " + detail + " [MONITORING INTERVAL IN SECONDS: " + text2 + "]")); } } } internal static class VoiceBoxNetwork { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnReady; public static HandleNamedMessageDelegate <1>__OnFire; public static HandleNamedMessageDelegate <2>__OnPlay; } private const string ReadyName = "CapsCrew_SLayer_Ready"; private const string FireName = "CapsCrew_SLayer_Fire"; private const string PlayName = "CapsCrew_SLayer_Play"; private const int ChunkSamples = 500; private const int WriterMax = 1280; private const int SendRate = 8000; private const int MaxSendSamples = 80000; private static bool _registered; private static float[]? _assemble; private static int _assembleGot; private static int _assembleTotal; private static int _assembleRate; private static ulong _assembleFrom; private static float[]? _sendSamples; private static int _sendRate; private static int _sendOffset; private static int _sendTotalChunks; private static int _sendSentChunks; private static readonly List SendPeers = new List(); private static ulong _sendFrom; internal static void TryRegister() { //IL_003b: 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_0046: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown if (_registered) { return; } NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.CustomMessagingManager != null) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__OnReady; if (obj == null) { HandleNamedMessageDelegate val = OnReady; <>O.<0>__OnReady = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("CapsCrew_SLayer_Ready", (HandleNamedMessageDelegate)obj); CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager; object obj2 = <>O.<1>__OnFire; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnFire; <>O.<1>__OnFire = val2; obj2 = (object)val2; } customMessagingManager2.RegisterNamedMessageHandler("CapsCrew_SLayer_Fire", (HandleNamedMessageDelegate)obj2); CustomMessagingManager customMessagingManager3 = singleton.CustomMessagingManager; object obj3 = <>O.<2>__OnPlay; if (obj3 == null) { HandleNamedMessageDelegate val3 = OnPlay; <>O.<2>__OnPlay = val3; obj3 = (object)val3; } customMessagingManager3.RegisterNamedMessageHandler("CapsCrew_SLayer_Play", (HandleNamedMessageDelegate)obj3); _registered = true; } } internal unsafe static void NotifyReady() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) try { TryRegister(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.IsServer) { if ((Object)(object)singleton != (Object)null && singleton.IsServer) { VoiceBoxDirector.MarkReady(singleton.LocalClientId); } return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, 64); try { ulong localClientId = singleton.LocalClientId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref localClientId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("CapsCrew_SLayer_Ready", 0uL, val, (NetworkDelivery)2); VoiceBoxLog.Note("READY", $"sent-to-host client={singleton.LocalClientId}"); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch (Exception ex) { VoiceBoxLog.Note("SKIP", "ready-error " + ex.Message); } } internal unsafe static void HostFire(ulong targetClientId) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) TryRegister(); if (!VoiceBox.IsOnMoon()) { VoiceBoxLog.Note("SKIP", "fire-not-on-moon"); return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { VoiceBoxLog.Note("SKIP", "fire-not-host"); return; } VoiceBoxLog.Note("FIRE", $"target={targetClientId}"); if (targetClientId == singleton.LocalClientId) { SendLocalSnippet(); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref targetClientId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("CapsCrew_SLayer_Fire", targetClientId, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void OnReady(ulong senderClientId, FastBufferReader reader) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); VoiceBoxDirector.MarkReady((num == 0L) ? senderClientId : num); } private static void OnFire(ulong senderClientId, FastBufferReader reader) { VoiceBoxLog.Note("FIRE", $"recv-host-fire sender={senderClientId}"); SendLocalSnippet(); } private static void SendLocalSnippet() { TryRegister(); VoiceBoxCache instance = VoiceBoxCache.Instance; NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)instance == (Object)null || (Object)(object)singleton == (Object)null || !instance.TryPick(out float[] samples, out int sampleRate)) { VoiceBoxLog.Note("SKIP", "send-no-snippet"); return; } samples = VoiceBoxCache.Resample(samples, sampleRate, 8000); sampleRate = 8000; int num = Mathf.Min(samples.Length, 80000); if (num < 8000) { VoiceBoxLog.Note("SKIP", "send-too-short"); return; } SendPeers.Clear(); foreach (ulong connectedClientsId in singleton.ConnectedClientsIds) { if (connectedClientsId != singleton.LocalClientId) { SendPeers.Add(connectedClientsId); } } if (SendPeers.Count == 0) { VoiceBoxLog.Note("SKIP", "send-no-peers"); return; } float[] array = new float[num]; Array.Copy(samples, array, num); _sendSamples = array; _sendRate = sampleRate; _sendOffset = 0; _sendFrom = singleton.LocalClientId; _sendTotalChunks = (num + 500 - 1) / 500; _sendSentChunks = 0; VoiceBoxLog.Note("SEND", $"queue samples={num} rate={sampleRate} secs={(float)num / (float)sampleRate:0.00} peers={SendPeers.Count} chunks={_sendTotalChunks}"); } internal static void ClearSend() { _sendSamples = null; _sendOffset = 0; SendPeers.Clear(); } internal unsafe static void PumpSend() { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) if (_sendSamples == null || SendPeers.Count == 0) { return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.CustomMessagingManager == null) { return; } int num = _sendSamples.Length; FastBufferWriter val = default(FastBufferWriter); for (int i = 0; i < 4; i++) { if (_sendSamples == null) { break; } if (_sendOffset >= num) { break; } int num2 = Mathf.Min(500, num - _sendOffset); if (num2 <= 0) { break; } foreach (ulong sendPeer in SendPeers) { int num3 = 24 + num2 * 2; ((FastBufferWriter)(ref val))..ctor(num3, (Allocator)2, 1280); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref _sendFrom, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref _sendRate, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref _sendOffset, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref num2, default(ForPrimitives)); for (int j = 0; j < num2; j++) { short num4 = (short)Mathf.Clamp(_sendSamples[_sendOffset + j] * 32767f, -32768f, 32767f); ((FastBufferWriter)(ref val)).WriteValueSafe(ref num4, default(ForPrimitives)); } singleton.CustomMessagingManager.SendNamedMessage("CapsCrew_SLayer_Play", sendPeer, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } _sendOffset += num2; _sendSentChunks++; } if (_sendSamples == null || _sendOffset >= num) { VoiceBoxLog.Note("SEND", $"done chunks={_sendSentChunks}/{_sendTotalChunks} samples={num}"); ClearSend(); } } private static void OnPlay(ulong senderClientId, FastBufferReader reader) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); int num2 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); int num3 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num3, default(ForPrimitives)); int num4 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num4, default(ForPrimitives)); int num5 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num5, default(ForPrimitives)); num3 = Mathf.Clamp(num3, 0, 80000); num4 = Mathf.Clamp(num4, 0, 80000); num5 = Mathf.Clamp(num5, 0, 500); if (num3 <= 0 || num5 <= 0 || num4 + num5 > num3) { VoiceBoxLog.Note("SKIP", $"recv-bad-chunk from={num} off={num4} len={num5} total={num3}"); return; } if (_assemble == null || _assembleFrom != num || _assembleTotal != num3) { _assemble = new float[num3]; _assembleGot = 0; _assembleTotal = num3; _assembleRate = ((num2 > 0) ? num2 : 16000); _assembleFrom = num; } short num6 = default(short); for (int i = 0; i < num5; i++) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref num6, default(ForPrimitives)); _assemble[num4 + i] = (float)num6 / 32768f; } _assembleGot += num5; if (_assembleGot < num3) { return; } float[] assemble = _assemble; ulong assembleFrom = _assembleFrom; int assembleRate = _assembleRate; _assemble = null; _assembleGot = 0; if (!VoiceBox.IsOnMoon()) { VoiceBoxLog.Note("SKIP", $"recv-not-on-moon from={assembleFrom}"); return; } ulong num7 = (((Object)(object)NetworkManager.Singleton != (Object)null) ? NetworkManager.Singleton.LocalClientId : ulong.MaxValue); if (assembleFrom != num7) { VoiceBoxSpeaker.Play(assembleFrom, assemble, assembleRate); } } } } namespace CapsCrew.KylesMom.Patches { [HarmonyPatch(typeof(FlowermanAI), "Start")] internal static class FlowermanStartPatch { [HarmonyPostfix] private static void AfterStart(FlowermanAI __instance) { KyleMomVisual.Ensure(__instance); } } [HarmonyPatch(typeof(FlowermanAI), "Update")] internal static class FlowermanUpdatePatch { [HarmonyPostfix] private static void AfterUpdate(FlowermanAI __instance) { KyleMomVisual.Ensure(__instance); } } [HarmonyPatch(typeof(EnemyAI), "EnableEnemyMesh")] internal static class EnableEnemyMeshPatch { [HarmonyPostfix] private static void AfterEnableMesh(EnemyAI __instance) { FlowermanAI val = (FlowermanAI)(object)((__instance is FlowermanAI) ? __instance : null); if (val != null) { KyleMomVisual.Ensure(val); } } } [HarmonyPatch(typeof(StartOfRound), "LateUpdate")] internal static class VoiceBoxLateUpdatePatch { [HarmonyPostfix] private static void AfterLateUpdate() { VoiceBox.Tick(); } } [HarmonyPatch(typeof(StartOfRound), "Start")] internal static class VoiceBoxStartPatch { [HarmonyPostfix] private static void AfterStart() { VoiceBoxCache.Ensure(); VoiceBoxNetwork.TryRegister(); VoiceBoxCache.Instance?.TrySubscribe(); } } [HarmonyPatch(typeof(GameNetworkManager), "Start")] internal static class VoiceBoxNetworkStartPatch { [HarmonyPostfix] private static void AfterNetworkStart() { VoiceBoxNetwork.TryRegister(); } } [HarmonyPatch(typeof(StartOfRound), "OnDisable")] internal static class VoiceBoxDisablePatch { [HarmonyPostfix] private static void AfterDisable() { VoiceBoxDirector.ClearRound(); } } [HarmonyPatch(typeof(StartOfRound), "ShipLeave")] internal static class VoiceBoxShipLeavePatch { [HarmonyPrefix] private static void BeforeShipLeave() { VoiceBoxDirector.StopProcess(); } } [HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")] internal static class VoiceBoxShipHasLeftPatch { [HarmonyPostfix] private static void AfterShipHasLeft() { VoiceBoxDirector.StopProcess(); } } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] internal static class VoiceBoxEndOfGamePatch { [HarmonyPrefix] private static void BeforeEndOfGame() { VoiceBoxDirector.StopProcess(); } } }