Decompiled source of Baby Steps Multiplayer Mod v1.2.2
Mods/BabyStepsMultiplayerClient.dll
Decompiled 13 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Numerics; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using BabyStepsMultiplayerClient; using BabyStepsMultiplayerClient.Audio; using BabyStepsMultiplayerClient.Components; using BabyStepsMultiplayerClient.Config; using BabyStepsMultiplayerClient.Extensions; using BabyStepsMultiplayerClient.Networking; using BabyStepsMultiplayerClient.Player; using BabyStepsMultiplayerClient.UI; using BabyStepsMultiplayerClient.UI.Elements; using Concentus.Enums; using Concentus.Structs; using HarmonyLib; using Il2Cpp; using Il2CppBabySteps.Core.Audio; using Il2CppCinemachine; using Il2CppFMOD; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppNWH.DWP2.WaterObjects; using Il2CppSystem; using Il2CppSystem.Collections; using Il2CppTMPro; using LiteNetLib; using LiteNetLib.Layers; using LiteNetLib.Utils; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using Tomlet; using Tomlet.Models; using Unity.LiveCapture.ARKitFaceCapture; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "BabyStepsMultiplayerClient", "1.2.1", "Caleb Orchard", "https://github.com/caleborchard/Baby-Steps-Multiplayer-Mod-Client")] [assembly: MelonGame("DefaultCompany", "BabySteps")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Caleb Orchard")] [assembly: AssemblyConfiguration("Retail - Release")] [assembly: AssemblyDescription("A MelonLoader mod for Baby Steps that adds multiplayer to the game.")] [assembly: AssemblyFileVersion("1.2.1")] [assembly: AssemblyInformationalVersion("1.2.1+21760fd091dd4dbcc427a3bb32bb141617698660")] [assembly: AssemblyProduct("BabyStepsMultiplayerClient")] [assembly: AssemblyTitle("BabyStepsMultiplayerClient")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/caleborchard/Baby-Steps-Multiplayer-Mod-Client")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 BabyStepsMultiplayerClient { public class Core : MelonMod { public const string SERVER_VERSION = "106"; public static string CLIENT_VERSION; public const string cloneText = "(Clone)"; public static Instance logger; public static UIManager uiManager; public static NetworkManager networkManager; private static bool _firstOpen; public override void OnLateInitializeMelon() { CLIENT_VERSION = ((MelonBase)this).Info.Version; logger = ((MelonBase)this).LoggerInstance; ManagedEnumerator.Register(); uiManager = new UIManager(); networkManager = new NetworkManager(); logger.Msg("Initialized!"); VersionCheck.CheckForUpdate(); } public override void OnGUI() { uiManager.Draw(); } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { if (!_firstOpen && sceneName.Contains("Title")) { _firstOpen = true; uiManager.serverConnectUI.IsOpen = true; } } public override void OnUpdate() { uiManager.Update(); networkManager.Update(); if (LocalPlayer.Instance != null) { LocalPlayer.Instance.Update(); } if (MelonDebug.IsEnabled()) { if (Input.GetKeyDown((KeyCode)284)) { networkManager.Connect(ModSettings.connection.Address.Value, ModSettings.connection.Port.Value, ModSettings.connection.Password.Value); } if (Input.GetKeyDown((KeyCode)285)) { networkManager.Disconnect(); } } } public override void OnLateUpdate() { if (LocalPlayer.Instance != null) { LocalPlayer.Instance.LateUpdate(); } networkManager.LateUpdate(); } public override void OnApplicationQuit() { networkManager.Disconnect(); } public static bool HasLoadedGame() { if ((Object)(object)Menu.me == (Object)null) { return false; } return Menu.me.gameInProgress; } public static void DebugMsg(string msg) { if (MelonDebug.IsEnabled()) { logger.Msg(msg); } } public static bool RegisterComponent<T>(params Type[] interfaces) where T : class { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown try { RegisterTypeOptions val = new RegisterTypeOptions(); val.set_LogSuccess(true); val.set_Interfaces(Il2CppInterfaceCollection.op_Implicit(interfaces)); ClassInjector.RegisterTypeInIl2Cpp<T>(val); } catch (Exception value) { logger.Error($"Exception while attempting to Register {typeof(T).Name}: {value}"); return false; } return true; } } public static class ModSettings { public static readonly ConnectionConfig connection = new ConnectionConfig(); public static readonly PlayerConfig player = new PlayerConfig(); public static readonly AudioConfig audio = new AudioConfig(); public static void Load() { connection.Load(); player.Load(); audio.Load(); } public static void Save() { connection.Save(); player.Save(); audio.Save(); } } } namespace BabyStepsMultiplayerClient.UI { public class RuntimeFoldout { private bool isExpanded; private string label; public RuntimeFoldout(string label, bool defaultState = false) { this.label = label; isExpanded = defaultState; } public bool Draw(Action contents) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) Rect rect = GUILayoutUtility.GetRect(new GUIContent(label), StyleManager.Styles.Button); if (GUI.Button(rect, "", StyleManager.Styles.Button)) { isExpanded = !isExpanded; } Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref rect)).x + 10f, ((Rect)(ref rect)).y, 20f, ((Rect)(ref rect)).height); GUI.Label(val, isExpanded ? "▼" : "▶", StyleManager.Styles.RuntimeFoldoutButton); GUIStyle val2 = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontStyle = StyleManager.Styles.Button.fontStyle, fontSize = StyleManager.Styles.Button.fontSize }; val2.normal.textColor = StyleManager.Styles.Button.normal.textColor; GUIStyle val3 = val2; GUI.Label(rect, label, val3); if (isExpanded && contents != null) { GUILayout.BeginVertical(StyleManager.Styles.Box, (Il2CppReferenceArray<GUILayoutOption>)null); contents(); GUILayout.EndVertical(); } return isExpanded; } public void SetLabel(string newLabel) { label = newLabel; } public void SetExpanded(bool expanded) { isExpanded = expanded; } } public class RuntimeWindow { private const float REFERENCE_HEIGHT = 1080f; public float ScrollbarWidth = 16f; public bool IsOpen; public bool IsDraggable = true; public bool ShouldDrawBox = true; public bool ShouldDrawScrollBar = true; public bool ShouldDrawContentBacker = true; public bool ShouldAutoResizeHeight; public float MinResizeHeight = 10f; public float MaxResizeHeight; public string Label; private float _contentHeight; private Rect _windowRect = default(Rect); private Vector2 _scrollPos; private Rect _windowHeaderRect = default(Rect); private Rect _windowContentRect = default(Rect); private Rect _windowScrollViewRect = default(Rect); private Rect _windowScrollRect = default(Rect); private Rect _scrollBarRect = default(Rect); private bool _hasClicked; private bool _isDragging; private Vector2 _dragOffset = default(Vector2); private Vector2 _posCache = default(Vector2); private Vector2 _sizeCache = default(Vector2); private float ScaleFactor => (float)Screen.height / 1080f; public Vector2 Position { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return _posCache; } set { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) _posCache.x = value.x; _posCache.y = value.y; ((Rect)(ref _windowRect)).position = _posCache; } } public Vector2 Size { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return _sizeCache; } set { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) _sizeCache.x = value.x; _sizeCache.y = value.y; ((Rect)(ref _windowRect)).size = _sizeCache; } } public RuntimeWindow(string label, int id, Vector2 defaultPos = default(Vector2), Vector2 defaultSize = default(Vector2), bool defaultState = false) { //IL_0038: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) Label = label; Position = defaultPos; Size = defaultSize; _contentHeight = defaultSize.y; IsOpen = defaultState; } public bool Draw() { //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Invalid comparison between Unknown and I4 //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) if (IsOpen) { Matrix4x4 matrix = GUI.matrix; float scaleFactor = ScaleFactor; GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(scaleFactor, scaleFactor, 1f)); try { RecalculateBounds(); if (Label == null) { Label = string.Empty; } if (ShouldDrawBox) { GUI.Box(_windowRect, Label, StyleManager.Styles.Box); } GUI.BeginGroup(_windowContentRect); if (ShouldDrawScrollBar && _contentHeight > ((Rect)(ref _windowContentRect)).height) { _scrollPos.y = GUI.VerticalScrollbar(_scrollBarRect, _scrollPos.y, ((Rect)(ref _scrollBarRect)).height, 0f, _contentHeight, StyleManager.Styles.VerticalScrollBar); } else { _scrollPos.y = 0f; } if (ShouldDrawContentBacker) { GUI.BeginGroup(_windowScrollRect, StyleManager.Styles.Box); } else { GUI.BeginGroup(_windowScrollRect); } GUILayout.BeginArea(_windowScrollViewRect); DrawContent(); if ((int)Event.current.type == 7) { Rect lastRect = GUILayoutUtility.GetLastRect(); _contentHeight = ((Rect)(ref lastRect)).y + ((Rect)(ref lastRect)).height; } GUILayout.EndArea(); GUI.EndGroup(); GUI.EndGroup(); if (ShouldAutoResizeHeight) { Vector2 size = Size; float num = ((Rect)(ref _windowHeaderRect)).height + ((Rect)(ref _windowScrollRect)).height + 10f; if (MaxResizeHeight > 0f && num > MaxResizeHeight) { num = MaxResizeHeight; } if (num < MinResizeHeight) { num = MinResizeHeight; } size.y = num; Size = size; } } finally { GUI.matrix = matrix; } } HandleDrag(); return IsOpen; } internal virtual void DrawContent() { } private void RecalculateBounds() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) Vector2 position = Position; Vector2 size = Size; ((Rect)(ref _windowHeaderRect)).x = position.x; ((Rect)(ref _windowHeaderRect)).y = position.y; ((Rect)(ref _windowHeaderRect)).width = size.x + 8f; ((Rect)(ref _windowHeaderRect)).height = 30f; ((Rect)(ref _windowContentRect)).x = ((Rect)(ref _windowHeaderRect)).x + 10f; ((Rect)(ref _windowContentRect)).y = ((Rect)(ref _windowHeaderRect)).y + ((Rect)(ref _windowHeaderRect)).height; ((Rect)(ref _windowContentRect)).width = ((Rect)(ref _windowHeaderRect)).width - 28f; ((Rect)(ref _windowContentRect)).height = size.y - (((Rect)(ref _windowHeaderRect)).height + 10f); if (ShouldDrawScrollBar && _contentHeight > ((Rect)(ref _windowContentRect)).height) { ref Rect windowContentRect = ref _windowContentRect; ((Rect)(ref windowContentRect)).width = ((Rect)(ref windowContentRect)).width + 5f; } ((Rect)(ref _windowScrollViewRect)).width = ((Rect)(ref _windowContentRect)).width; ((Rect)(ref _windowScrollViewRect)).height = _contentHeight; if (ShouldDrawScrollBar && _contentHeight > ((Rect)(ref _windowContentRect)).height) { ref Rect windowScrollViewRect = ref _windowScrollViewRect; ((Rect)(ref windowScrollViewRect)).width = ((Rect)(ref windowScrollViewRect)).width - (ScrollbarWidth + 5f); } ((Rect)(ref _windowScrollRect)).x = ((Rect)(ref _windowScrollViewRect)).x; ((Rect)(ref _windowScrollRect)).y = 0f - _scrollPos.y; ((Rect)(ref _windowScrollRect)).width = ((Rect)(ref _windowScrollViewRect)).width; ((Rect)(ref _windowScrollRect)).height = _contentHeight; ((Rect)(ref _scrollBarRect)).x = ((Rect)(ref _windowScrollViewRect)).width + 5f; ((Rect)(ref _scrollBarRect)).width = ScrollbarWidth; ((Rect)(ref _scrollBarRect)).height = ((Rect)(ref _windowContentRect)).height; } private void HandleDrag() { //IL_002d: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (!IsOpen || !IsDraggable) { _isDragging = false; return; } float scaleFactor = ScaleFactor; Vector2 val = Vector2.op_Implicit(Input.mousePosition); Vector2 val2 = new Vector2(val.x, (float)Screen.height - val.y) / scaleFactor; if (_hasClicked) { if (Input.GetMouseButtonUp(0)) { _hasClicked = false; _isDragging = false; } } else if (Input.GetMouseButtonDown(0)) { _hasClicked = true; if (((Rect)(ref _windowHeaderRect)).Contains(val2)) { _isDragging = true; _dragOffset.x = val2.x - Position.x; _dragOffset.y = val2.y - Position.y; } } if (_isDragging) { Vector2 position = Position; position.x = val2.x - _dragOffset.x; position.y = val2.y - _dragOffset.y; Position = position; } } } internal static class StyleManager { internal static class Fonts { internal static Font Arial { get; private set; } internal static void Prepare() { if ((Object)(object)Arial == (Object)null) { Arial = Resources.GetBuiltinResource<Font>("Arial.ttf"); } } } internal static class Styles { internal static GUIStyle Label { get; private set; } internal static GUIStyle MiddleCenterLabel { get; private set; } internal static GUIStyle TextField { get; private set; } internal static GUIStyle MiddleLeftTextField { get; private set; } internal static GUIStyle Box { get; private set; } internal static GUIStyle Button { get; private set; } internal static GUIStyle ButtonLeftCenteredText { get; private set; } internal static GUIStyle VerticalScrollBar { get; private set; } internal static GUIStyle HorizontalSlider { get; private set; } internal static GUIStyle HorizontalSliderThumb { get; private set; } internal static GUIStyle RuntimeFoldoutButton { get; private set; } internal static void Prepare() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0045: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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_0135: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Expected O, but got Unknown //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Expected O, but got Unknown if (Label == null) { Label = new GUIStyle(GUI.skin.label) { font = Fonts.Arial, normal = new GUIStyleState { textColor = Color.white } }; } if (MiddleCenterLabel == null) { MiddleCenterLabel = new GUIStyle(Label) { alignment = (TextAnchor)4 }; } if (Box == null) { Box = new GUIStyle(GUI.skin.box) { font = Fonts.Arial }; } if (Button == null) { Button = new GUIStyle(GUI.skin.button) { font = Fonts.Arial }; } if (ButtonLeftCenteredText == null) { ButtonLeftCenteredText = new GUIStyle(GUI.skin.button) { font = Fonts.Arial, alignment = (TextAnchor)3 }; } if (HorizontalSlider == null) { HorizontalSlider = new GUIStyle(GUI.skin.horizontalSlider) { font = Fonts.Arial, fixedHeight = 20f }; } if (HorizontalSliderThumb == null) { HorizontalSliderThumb = new GUIStyle(GUI.skin.horizontalSliderThumb) { font = Fonts.Arial, fixedHeight = 20f, fixedWidth = 20f }; } if (VerticalScrollBar == null) { VerticalScrollBar = new GUIStyle(GUI.skin.verticalScrollbar) { font = Fonts.Arial }; } if (TextField == null) { TextField = new GUIStyle(GUI.skin.textField) { font = Fonts.Arial }; } if (MiddleLeftTextField == null) { MiddleLeftTextField = new GUIStyle(TextField) { alignment = (TextAnchor)3 }; } if (RuntimeFoldoutButton == null) { RuntimeFoldoutButton = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)3 }; } } } } public class UIManager { public bool showChatTab; public PlayersTabUI playersTabUI { get; private set; } public ServerConnectUI serverConnectUI { get; private set; } public NotificationUI notificationsUI { get; private set; } public ChatTabUI chatTabUI { get; private set; } public UIManager() { StyleManager.Fonts.Prepare(); serverConnectUI = new ServerConnectUI(); serverConnectUI.LoadConfig(); notificationsUI = new NotificationUI(); playersTabUI = new PlayersTabUI(); chatTabUI = new ChatTabUI(); } public void Draw() { StyleManager.Styles.Prepare(); notificationsUI.DrawUI(); serverConnectUI.Draw(); playersTabUI.Draw(); if (showChatTab) { chatTabUI.DrawUI(); } } public void Update() { if (!showChatTab && Input.GetKeyDown((KeyCode)283)) { serverConnectUI.IsOpen = !serverConnectUI.IsOpen; } if (serverConnectUI.IsOpen || Core.networkManager.client == null) { playersTabUI.IsOpen = false; showChatTab = false; return; } if (!showChatTab && Input.GetKeyDown((KeyCode)116)) { showChatTab = true; } playersTabUI.IsOpen = !showChatTab && Input.GetKey((KeyCode)9); } public void ApplyCollisionToggle(RemotePlayer player, bool collisionsEnabled) { if (collisionsEnabled) { player.netCollisionsEnabled = true; notificationsUI.AddMessage(player.displayName + " has enabled collisions"); if (ModSettings.player.Collisions.Value) { player.EnableCollision(); } else { player.DisableCollision(); } } else { player.netCollisionsEnabled = false; notificationsUI.AddMessage(player.displayName + " has disabled collisions"); player.DisableCollision(); } } } } namespace BabyStepsMultiplayerClient.UI.Elements { public class ChatTabUI { private string message = ""; private Rect textFieldRect; private GUIStyle textFieldStyle; public void DrawUI() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown if (textFieldStyle == null) { textFieldStyle = new GUIStyle(StyleManager.Styles.MiddleLeftTextField); } textFieldStyle.fontSize = Mathf.RoundToInt((float)Screen.height * 0.02f); HandleChatInput(); float num = (float)Screen.width * 0.4f; float num2 = (float)Screen.height * 0.05f; float num3 = ((float)Screen.width - num) / 2f; float num4 = (float)Screen.height - num2 - 20f; textFieldRect = new Rect(num3, num4, num, num2); GUILayout.BeginArea(textFieldRect); GUI.SetNextControlName("ChatInput"); message = GUILayout.TextField(message, 150, textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true) }); GUILayout.EndArea(); if ((int)Event.current.type == 7 && GUI.GetNameOfFocusedControl() != "ChatInput") { GUI.FocusControl("ChatInput"); } } private void HandleChatInput() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 Event current = Event.current; if ((int)current.type == 4) { if ((int)current.keyCode == 13 || (int)current.keyCode == 271) { SendCurrentMessage(); Core.uiManager.showChatTab = false; current.Use(); } else if ((int)current.keyCode == 27) { Core.uiManager.showChatTab = false; current.Use(); } } } public void SendCurrentMessage() { if (!string.IsNullOrWhiteSpace(message)) { Core.networkManager.SendChatMessage(message); Core.uiManager.notificationsUI.AddMessage("You: " + message); message = ""; } } } public class NotificationUI { private class Message { public string Text; public float TimeAdded; public Color Color; public float HoldDuration; } private const float REFERENCE_HEIGHT = 1080f; private const float fadeDuration = 1f; private readonly List<Message> messages = new List<Message>(); private readonly List<Message> messagesToRemove = new List<Message>(); private static float GetTime() { return Time.unscaledTime; } public void AddMessage(string message, float? holdDuration = null, Color? color = null) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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) Core.logger.Msg(message); messages.Add(new Message { Text = message, HoldDuration = holdDuration.GetValueOrDefault(3f), Color = (Color)(((??)color) ?? Color.white) }); } public void DrawUI() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) float num = (float)Screen.height / 1080f; Matrix4x4 matrix = GUI.matrix; GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f)); try { float time = GetTime(); int num2 = 10; float num3 = (float)Screen.width / num; for (int num4 = messages.Count - 1; num4 >= 0; num4--) { Message message = messages[num4]; if (message.TimeAdded <= 0f) { message.TimeAdded = time; } float age = time - message.TimeAdded; if (FadeMessage(message.HoldDuration, age, out var alpha)) { messagesToRemove.Add(message); } else { GUI.color = new Color(message.Color.r, message.Color.g, message.Color.b, alpha); GUI.Label(new Rect(10f, (float)num2, num3 - 20f, 25f), message.Text, StyleManager.Styles.Label); num2 += 20; } } } finally { GUI.matrix = matrix; GUI.color = Color.white; } if (messagesToRemove.Count > 0) { messages.RemoveAll(messagesToRemove.Contains); messagesToRemove.Clear(); } } private static bool FadeMessage(float HoldDuration, float age, out float alpha) { if (age < HoldDuration) { alpha = 1f; } else { float num = age - HoldDuration; alpha = Mathf.Clamp01(1f - num / 1f); if (alpha <= 0f) { return true; } } return false; } } public class PlayersTabUI : RuntimeWindow { private static Vector2 defaultSize = new Vector2(300f, 10f); public PlayersTabUI() : base("Connected Players", 2, new Vector2((float)Screen.width / 2f - defaultSize.x / 2f, 20f), defaultSize) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) IsDraggable = false; ShouldDrawScrollBar = false; ShouldAutoResizeHeight = true; MinResizeHeight = defaultSize.y; MaxResizeHeight = Screen.height - 20; } internal override void DrawContent() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) float num = (float)Screen.height / 1080f; Vector2 position = base.Position; position.x = (float)Screen.width / num / 2f - base.Size.x / 2f; base.Position = position; MaxResizeHeight = (float)Screen.height - position.y - 20f; int value = 0; if (LocalPlayer.Instance != null && (Object)(object)LocalPlayer.Instance.headBone != (Object)null) { value = (int)(LocalPlayer.Instance.headBone.position.y - 120f); } Label = $"Connected Players [Y:{value}]"; GUILayout.Space(1f); if (Core.networkManager.players.Count == 0) { GUILayout.Label("No players connected.", StyleManager.Styles.MiddleCenterLabel, (Il2CppReferenceArray<GUILayoutOption>)null); } else { foreach (KeyValuePair<byte, RemotePlayer> player in Core.networkManager.players) { RemotePlayer value2 = player.Value; if (value2 != null) { int value3 = 0; if ((Object)(object)value2.rootBone != (Object)null) { value3 = (int)value2.rootBone.position.y - 120; } GUILayout.Label($"[Y:{value3}] {value2.displayName}", StyleManager.Styles.MiddleCenterLabel, (Il2CppReferenceArray<GUILayoutOption>)null); } } } GUILayout.Space(2f); } } public class ServerConnectUI : RuntimeWindow { public RuntimeFoldout serverInfoFoldout = new RuntimeFoldout("Server Information"); public RuntimeFoldout audioSettingsFoldout = new RuntimeFoldout("Audio Settings"); public RuntimeFoldout microphoneDevicesFoldout = new RuntimeFoldout("Microphone Devices"); public RuntimeFoldout generalSettingsFoldout = new RuntimeFoldout("General Settings"); public RuntimeFoldout playerCustomizationFoldout = new RuntimeFoldout("Player Customization", defaultState: true); private string[] availableDevices = new string[0]; private bool isWaitingForKey = false; private float currentPeak = 0f; private float peakDecayRate = 0.95f; public ServerConnectUI() : base("Server Join Panel v" + Core.CLIENT_VERSION, 0, new Vector2(30f, 30f), new Vector2(250f, 400f)) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) ShouldDrawContentBacker = false; } internal override void DrawContent() { //IL_002d: 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_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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (isWaitingForKey) { foreach (KeyCode value in Enum.GetValues(typeof(KeyCode))) { KeyCode val = value; if (Input.GetKeyDown(val) && (int)val != 0 && (int)val != 323) { ModSettings.audio.PushToTalkKey.Value = ((object)(KeyCode)(ref val)).ToString(); if (LocalPlayer.Instance != null) { LocalPlayer.Instance.SetPushToTalkKey(val); } isWaitingForKey = false; break; } } } bool flag = Core.networkManager.client != null; string text = (flag ? "Disconnect" : "Connect"); if (GUILayout.Button(text, StyleManager.Styles.Button, Array.Empty<GUILayoutOption>())) { if (flag) { Core.networkManager.Disconnect(); } else { Core.logger.Msg($"{ModSettings.player.Nickname.Value}, {ModSettings.connection.Address.Value}:{ModSettings.connection.Port.Value}"); SaveConfig(); Core.networkManager.Connect(ModSettings.connection.Address.Value, ModSettings.connection.Port.Value, ModSettings.connection.Password.Value); } } GUILayout.Space(10f); serverInfoFoldout.Draw(HandleServerInfo); GUILayout.Space(10f); audioSettingsFoldout.Draw(HandleAudioSettings); GUILayout.Space(10f); generalSettingsFoldout.Draw(HandleGeneralSettings); GUILayout.Space(10f); playerCustomizationFoldout.Draw(HandlePlayerCustomization); } private void HandleServerInfo() { GUILayout.Label("Server IP:", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); ModSettings.connection.Address.Value = GUILayout.TextField(ModSettings.connection.Address.Value, 32, StyleManager.Styles.TextField, Array.Empty<GUILayoutOption>()); GUILayout.Label("Server Port:", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); string s = GUILayout.TextField(ModSettings.connection.Port.Value.ToString(), 5, StyleManager.Styles.TextField, Array.Empty<GUILayoutOption>()); if (int.TryParse(s, out var result)) { ModSettings.connection.Port.Value = result; } GUILayout.Label("Password (Optional):", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); ModSettings.connection.Password.Value = GUILayout.PasswordField(ModSettings.connection.Password.Value, '*', 32, StyleManager.Styles.TextField, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); } private void HandleAudioSettings() { GUI.enabled = LocalPlayer.Instance != null; string text = (ModSettings.audio.MicrophoneEnabled.Value ? "Disable" : "Enable") + " Microphone"; if (GUILayout.Button(text, StyleManager.Styles.Button, Array.Empty<GUILayoutOption>())) { ModSettings.audio.MicrophoneEnabled.Value = !ModSettings.audio.MicrophoneEnabled.Value; LocalPlayer.Instance?.SetMicrophoneEnabled(ModSettings.audio.MicrophoneEnabled.Value); } GUILayout.Space(5f); if (GUILayout.Button(ModSettings.audio.Deafened.Value ? "Undeafen" : "Deafen", StyleManager.Styles.Button, Array.Empty<GUILayoutOption>())) { ModSettings.audio.Deafened.Value = !ModSettings.audio.Deafened.Value; } GUILayout.Space(5f); if (GUILayout.Button((ModSettings.audio.PushToTalk.Value ? "Disable" : "Enable") + " Push to Talk", StyleManager.Styles.Button, Array.Empty<GUILayoutOption>())) { ModSettings.audio.PushToTalk.Value = !ModSettings.audio.PushToTalk.Value; LocalPlayer.Instance?.SetPushToTalkEnabled(ModSettings.audio.PushToTalk.Value); } GUILayout.Space(5f); GUI.enabled = LocalPlayer.Instance != null && ModSettings.audio.PushToTalk.Value; GUILayout.BeginHorizontal((Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.Label("Push to Talk Key:", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); string text2 = (isWaitingForKey ? "Press any key..." : ModSettings.audio.PushToTalkKey.Value); if (GUILayout.Button(text2, StyleManager.Styles.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) })) { isWaitingForKey = true; } GUILayout.EndHorizontal(); GUILayout.Space(5f); GUI.enabled = LocalPlayer.Instance != null; GUILayout.Label($"Microphone Gain: {ModSettings.audio.MicrophoneGain.Value:F2}x", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); float num = GUILayout.HorizontalSlider(ModSettings.audio.MicrophoneGain.Value, 0f, 3f, StyleManager.Styles.HorizontalSlider, StyleManager.Styles.HorizontalSliderThumb, Array.Empty<GUILayoutOption>()); if (num != ModSettings.audio.MicrophoneGain.Value) { ModSettings.audio.MicrophoneGain.Value = num; LocalPlayer.Instance?.mic.SetGain(num); } GUILayout.Space(5f); DrawPeakMeter(); GUILayout.Space(5f); microphoneDevicesFoldout.Draw(HandleMicrophoneDevices); GUI.enabled = true; } private void DrawPeakMeter() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) if (LocalPlayer.Instance != null && LocalPlayer.Instance.mic != null && LocalPlayer.Instance.mic.IsRecording()) { UpdatePeakLevel(); } else { currentPeak = 0f; } GUILayout.BeginHorizontal((Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.Label("Level:", StyleManager.Styles.Label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) }); Rect rect = GUILayoutUtility.GetRect(180f, 20f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = new Color(0.2f, 0.2f, 0.2f, 1f); GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; float num = 20f * Mathf.Log10(Mathf.Max(currentPeak, 0.0001f)); float num2 = Mathf.Clamp01((num + 60f) / 60f); if (num2 > 0.01f) { Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width * num2, ((Rect)(ref rect)).height); Color color; if (num2 < 0.666f) { color = Color.green; } else if (num2 < 0.85f) { float num3 = (num2 - 0.666f) / 0.18400002f; color = Color.Lerp(Color.green, Color.yellow, num3); } else { float num4 = (num2 - 0.85f) / 0.14999998f; color = Color.Lerp(Color.yellow, Color.red, num4); } GUI.color = color; GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; } DrawTickMark(rect, 0.666f); DrawTickMark(rect, 0.85f); GUILayout.EndHorizontal(); string text = ((num > -60f) ? $"{num:F1} dB" : "-inf dB"); GUILayout.Label(text, StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); } private void DrawTickMark(Rect meterRect, float position) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) float num = ((Rect)(ref meterRect)).x + ((Rect)(ref meterRect)).width * position; Rect val = default(Rect); ((Rect)(ref val))..ctor(num - 1f, ((Rect)(ref meterRect)).y, 2f, ((Rect)(ref meterRect)).height); GUI.color = new Color(0.5f, 0.5f, 0.5f, 0.8f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; } private void UpdatePeakLevel() { currentPeak *= peakDecayRate; BBSMicrophoneCapture bBSMicrophoneCapture = LocalPlayer.Instance?.mic; if (bBSMicrophoneCapture != null && bBSMicrophoneCapture.IsRecording()) { float lastFramePeak = bBSMicrophoneCapture.GetLastFramePeak(); if (lastFramePeak > currentPeak) { currentPeak = lastFramePeak; } } } private void HandleMicrophoneDevices() { if (LocalPlayer.Instance == null || LocalPlayer.Instance.mic == null) { return; } if (availableDevices.Length < 1) { availableDevices = LocalPlayer.Instance.mic.GetAvailableDevices(); } if (availableDevices.Length != 0) { ModSettings.audio.SelectedMicrophoneIndex.Value = Mathf.Clamp(ModSettings.audio.SelectedMicrophoneIndex.Value, 0, availableDevices.Length - 1); int num = GUILayout.SelectionGrid(ModSettings.audio.SelectedMicrophoneIndex.Value, Il2CppStringArray.op_Implicit(availableDevices), 1, StyleManager.Styles.ButtonLeftCenteredText, Array.Empty<GUILayoutOption>()); if (num != ModSettings.audio.SelectedMicrophoneIndex.Value) { ModSettings.audio.SelectedMicrophoneIndex.Value = num; LocalPlayer.Instance.SetMicrophoneDevice(ModSettings.audio.SelectedMicrophoneIndex.Value); } } } private void HandleGeneralSettings() { GUI.enabled = Core.networkManager.client != null; if (GUILayout.Button((ModSettings.player.Collisions.Value ? "Disable" : "Enable") + " Collisions", StyleManager.Styles.Button, Array.Empty<GUILayoutOption>())) { ModSettings.player.Collisions.Value = !ModSettings.player.Collisions.Value; Core.networkManager.SendCollisionToggle(ModSettings.player.Collisions.Value); foreach (KeyValuePair<byte, RemotePlayer> player in Core.networkManager.players) { if (ModSettings.player.Collisions.Value && player.Value.netCollisionsEnabled) { player.Value.EnableCollision(); } else { player.Value.DisableCollision(); } } } GUILayout.Space(5f); GUI.enabled = true; GUI.enabled = Core.networkManager.client != null; if (GUILayout.Button((ModSettings.player.CutscenePlayerVisibility.Value ? "Enable" : "Disable") + " Player Cutscene Visibility", StyleManager.Styles.Button, Array.Empty<GUILayoutOption>())) { ModSettings.player.CutscenePlayerVisibility.Value = !ModSettings.player.CutscenePlayerVisibility.Value; } GUILayout.Space(5f); GUI.enabled = true; GUI.enabled = Core.networkManager.client != null; if (GUILayout.Button((ModSettings.player.ShowNametags.Value ? "Disable" : "Enable") + " Nametag Visibility", StyleManager.Styles.Button, Array.Empty<GUILayoutOption>())) { ModSettings.player.ShowNametags.Value = !ModSettings.player.ShowNametags.Value; } GUILayout.Space(5f); GUI.enabled = true; } private void HandlePlayerCustomization() { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) GUI.enabled = Core.networkManager.client != null; if (GUILayout.Button("Update Name & Appearance", StyleManager.Styles.Button, Array.Empty<GUILayoutOption>()) && Core.networkManager.client != null) { SaveConfig(); Core.networkManager.mainThreadActions.Enqueue(delegate { Core.networkManager.SendPlayerInformation(); if (LocalPlayer.Instance != null) { LocalPlayer.Instance.ApplySuitColor(); } }); Core.uiManager.notificationsUI.AddMessage("Your appearance has been updated"); } GUILayout.Space(5f); GUI.enabled = true; GUILayout.Label("Nickname:", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); ModSettings.player.Nickname.Value = FilterKeyboardCharacters(GUILayout.TextField(ModSettings.player.Nickname.Value, 20, StyleManager.Styles.TextField, Array.Empty<GUILayoutOption>())); Color value = ModSettings.player.SuitColor.Value; if (value.a != 1f) { value.a = 1f; } GUILayout.Space(5f); GUILayout.BeginHorizontal((Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.Label("Suit Tint:", StyleManager.Styles.Label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUI.color = value; GUILayout.Label("████████", StyleManager.Styles.MiddleCenterLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUI.color = Color.white; GUILayout.EndHorizontal(); GUILayout.Space(2f); GUILayout.Label($"Red: {(int)(value.r * 255f)}", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); value.r = GUILayout.HorizontalSlider(value.r, 0f, 1f, StyleManager.Styles.HorizontalSlider, StyleManager.Styles.HorizontalSliderThumb, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Green: {(int)(value.g * 255f)}", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); value.g = GUILayout.HorizontalSlider(value.g, 0f, 1f, StyleManager.Styles.HorizontalSlider, StyleManager.Styles.HorizontalSliderThumb, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Blue: {(int)(value.b * 255f)}", StyleManager.Styles.Label, (Il2CppReferenceArray<GUILayoutOption>)null); value.b = GUILayout.HorizontalSlider(value.b, 0f, 1f, StyleManager.Styles.HorizontalSlider, StyleManager.Styles.HorizontalSliderThumb, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); ModSettings.player.SuitColor.Value = value; } public void SaveConfig() { ModSettings.Save(); } public void LoadConfig() { ModSettings.Load(); } private string FilterKeyboardCharacters(string input) { return Regex.Replace(input, "[^\\p{L}\\p{N}!@#\\$%\\^&\\*\\(\\)_\\+\\-=\\[\\]{};:'\",<.>/?\\\\|`~ ]", ""); } } } namespace BabyStepsMultiplayerClient.Player { public class BasePlayer { public GameObject baseObject; public Transform baseMesh; public SkinnedMeshRenderer skinnedMeshRenderer; public GameObject jiminyRibbon; public MeshRenderer nateGlasses; public Transform particleHouse; public Transform particleCrushers; public ParticleParty particleParty; public Material hairMaterial; public Material suitMaterial; public Color baseColor = Color.white; public Color playerColor = Color.white; public List<Transform> boneChildren; public List<Transform> puppetBones; public Transform puppetMaster; public Transform headBone; public Transform rootBone; public Transform spineBone; public (Transform, Transform) handBones; public (Transform, Transform) footBones; public (Transform, Transform) eyeLids; public (Transform, Transform) eyeBalls; public (SkinnedMeshRenderer, SkinnedMeshRenderer) eyeBallRenderers; public Dictionary<string, Transform> boneMudMeshes; public Material[] meshMaterials; public Transform jawMaster; public Transform mchJawMaster; private const float CLOSED_JAW_X = 36.65f; private const float OPEN_JAW_X = 5f; private const float OPEN_LIP_X = 15f; public FaceActor faceActor; private int idxJawOpen = -1; private int idxMouthClose = -1; public virtual void Initialize() { if ((Object)(object)baseObject == (Object)null) { return; } if ((Object)(object)puppetMaster == (Object)null) { puppetMaster = baseObject.transform.FindChild("PuppetMaster"); } if ((Object)(object)baseMesh == (Object)null) { baseMesh = baseObject.transform.Find("IKTargets/HipTarget/NathanAnimIK_October2022"); } if (!((Object)(object)baseMesh != (Object)null)) { return; } if ((Object)(object)skinnedMeshRenderer == (Object)null) { skinnedMeshRenderer = ((Component)baseMesh.Find("Nathan.001")).GetComponent<SkinnedMeshRenderer>(); } if ((Object)(object)particleHouse == (Object)null) { particleHouse = baseObject.transform.Find("ParticleHouse"); } if ((Object)(object)particleHouse != (Object)null) { if ((Object)(object)particleCrushers == (Object)null) { particleCrushers = particleHouse.Find("Crushers"); } if ((Object)(object)particleParty == (Object)null) { particleParty = ((Component)particleHouse).GetComponent<ParticleParty>(); } } if ((Object)(object)eyeLids.Item1 == (Object)null) { eyeLids.Item1 = ((Component)baseMesh).transform.FindChild("Nathan_EyeLOuter"); } if ((Object)(object)eyeLids.Item2 == (Object)null) { eyeLids.Item2 = ((Component)baseMesh).transform.FindChild("Nathan_EyeROuter"); } if ((Object)(object)eyeBalls.Item1 == (Object)null) { eyeBalls.Item1 = ((Component)baseMesh).transform.FindChild("Nathan_EyeLInner"); } if ((Object)(object)eyeBalls.Item1 != (Object)null) { eyeBallRenderers.Item1 = ((Component)eyeBalls.Item1).GetComponent<SkinnedMeshRenderer>(); } if ((Object)(object)eyeBalls.Item2 == (Object)null) { eyeBalls.Item2 = ((Component)baseMesh).transform.FindChild("Nathan_EyeRInner"); } if ((Object)(object)eyeBalls.Item2 != (Object)null) { eyeBallRenderers.Item2 = ((Component)eyeBalls.Item2).GetComponent<SkinnedMeshRenderer>(); } if ((Object)(object)jiminyRibbon == (Object)null) { Transform val = baseMesh.FindChildByKeyword("JiminysCricketsRibbon"); if ((Object)(object)val != (Object)null) { jiminyRibbon = ((Component)val).gameObject; } } if ((Object)(object)faceActor == (Object)null) { faceActor = baseObject.GetComponentInChildren<FaceActor>(true); } } protected void InitializeJawMasters() { if (!((Object)(object)headBone == (Object)null)) { Transform val = headBone.Find("ORG-face"); if ((Object)(object)val != (Object)null) { jawMaster = val.Find("jaw_master"); mchJawMaster = val.Find("MCH-jaw_master"); } } } public void SetMouthOpen(float openAmount) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)jawMaster == (Object)null) && !((Object)(object)mchJawMaster == (Object)null)) { openAmount = Mathf.Clamp01(openAmount); float num = Mathf.Lerp(36.65f, 5f, openAmount); float num2 = Mathf.Lerp(36.65f, 15f, openAmount); jawMaster.localEulerAngles = new Vector3(num, 180f, 180f); mchJawMaster.localEulerAngles = new Vector3(num2, 180f, 180f); } } public void CloseMouth() { SetMouthOpen(0f); } public virtual void Dispose() { } public virtual void Update() { } public virtual void LateUpdate() { } public Texture2D CloneSuitTexture() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)suitMaterial == (Object)null) { return null; } Texture texture = suitMaterial.GetTexture("_AlbedoMap"); Texture2D val = new Texture2D(texture.width, texture.height, (TextureFormat)5, false); RenderTexture val2 = new RenderTexture(texture.width, texture.height, 0); RenderTexture active = RenderTexture.active; Graphics.Blit(texture, val2); RenderTexture.active = val2; val.ReadPixels(new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), 0, 0); val.Apply(); RenderTexture.active = active; val2.Release(); return val; } public void SetHairHat(float hatMax, Vector4 hatUp) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) SetHairValues(hairMaterial, hatMax, hatUp); } public static void SetHairValues(Material mat, float hatMax, Vector4 hatUp) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)mat == (Object)null)) { mat.SetFloat("_HatMax", hatMax); mat.SetVector("_HatUp", hatUp); ((Object)mat).MarkDirty(); } } public Color GetSuitColor() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return playerColor; } public virtual void SetSuitColor(Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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) playerColor = color; if ((Object)(object)suitMaterial != (Object)null && suitMaterial.color != playerColor) { suitMaterial.color = playerColor; } } public void ResetSuitColor() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)suitMaterial == (Object)null)) { suitMaterial.color = baseColor; } } public void FadeByDistance(float distance) { if (!((Object)(object)baseObject == (Object)null)) { float num = 1.3f; float num2 = 0.7f; float opacity = Mathf.Clamp01((distance - num2) / (num - num2)); SetOpacity(opacity); } } public virtual void SetOpacity(float opacity) { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skinnedMeshRenderer != (Object)null) { Il2CppReferenceArray<Material> materials = ((Renderer)skinnedMeshRenderer).materials; for (int i = 0; i < ((Il2CppArrayBase<Material>)(object)materials).Count; i++) { Material val = ((Il2CppArrayBase<Material>)(object)materials)[i]; if (val.HasProperty("_DitherAlpha")) { val.SetFloat("_DitherAlpha", opacity); } else if (val.HasProperty("_Cutoff")) { val.SetFloat("_Cutoff", Mathf.Lerp(1.05f, 0.12f, opacity * opacity)); } } } if ((Object)(object)nateGlasses != (Object)null) { Il2CppReferenceArray<Material> materials2 = ((Renderer)nateGlasses).materials; if (((Il2CppArrayBase<Material>)(object)materials2).Length > 1 && (Object)(object)((Il2CppArrayBase<Material>)(object)materials2)[1] != (Object)null && ((Il2CppArrayBase<Material>)(object)materials2)[1].HasProperty("_DitherAlpha")) { ((Il2CppArrayBase<Material>)(object)materials2)[1].SetFloat("_DitherAlpha", opacity); } } if ((Object)(object)eyeBallRenderers.Item1 != (Object)null && (Object)(object)((Renderer)eyeBallRenderers.Item1).material != (Object)null) { Color color = ((Renderer)eyeBallRenderers.Item1).material.GetColor("_Color"); color.a = opacity; ((Renderer)eyeBallRenderers.Item1).material.SetColor("_Color", color); } if ((Object)(object)eyeBallRenderers.Item2 != (Object)null && (Object)(object)((Renderer)eyeBallRenderers.Item2).material != (Object)null) { Color color2 = ((Renderer)eyeBallRenderers.Item2).material.GetColor("_Color"); color2.a = opacity; ((Renderer)eyeBallRenderers.Item2).material.SetColor("_Color", color2); } } private static Transform[] ExtractValidBones(Transform[] meshBones, Transform meshRoot) { Transform[] array = (Transform[])(object)new Transform[meshBones.Length]; HashSet<Transform> hashSet = new HashSet<Transform>(meshBones); Queue<Transform> queue = new Queue<Transform>(); Transform item = meshRoot.Find("root/root.x"); queue.Enqueue(item); int num = 0; while (queue.Count > 0 && num < array.Length) { Transform val = queue.Dequeue(); if (!IsBoneNameValid(((Object)val).name)) { continue; } if (hashSet.Contains(val)) { array[num++] = val; } if (!(((Object)val).name != "ORG-face") && !((Object)val).name.Contains("hand") && !((Object)val).name.Contains("foot")) { continue; } for (int i = 0; i < val.childCount; i++) { Transform child = val.GetChild(i); if (hashSet.Contains(child)) { queue.Enqueue(child); } } } if (num < array.Length) { Array.Resize(ref array, num); } return array; } private static bool IsBoneNameValid(string name) { if (name == null) { return false; } string text = name.ToLowerInvariant(); string[] array = new string[10] { "belly", "butt", "twist", "boob", "backfat", "index", "middle", "pinky", "thumb", "ring" }; string[] array2 = array; foreach (string value in array2) { if (text.Contains(value)) { return false; } } return !string.Equals(name, "JiminysCricketsRibbon"); } public void ResetBonesToBind() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skinnedMeshRenderer == (Object)null || (Object)(object)LocalPlayer.Instance.skinnedMeshRenderer == (Object)null) { return; } Transform[] array = Il2CppArrayBase<Transform>.op_Implicit((Il2CppArrayBase<Transform>)(object)skinnedMeshRenderer.bones); Matrix4x4[] array2 = Il2CppArrayBase<Matrix4x4>.op_Implicit((Il2CppArrayBase<Matrix4x4>)(object)LocalPlayer.Instance.skinnedMeshRenderer.sharedMesh.bindposes); Transform val = skinnedMeshRenderer.rootBone; for (int i = 0; i < array.Length; i++) { Transform val2 = array[i]; Matrix4x4 inverse = ((Matrix4x4)(ref array2[i])).inverse; Vector3 localPosition; Quaternion localRotation; if ((Object)(object)val2.parent == (Object)null) { localPosition = Vector4.op_Implicit(((Matrix4x4)(ref inverse)).GetColumn(3)); localRotation = Quaternion.LookRotation(Vector4.op_Implicit(((Matrix4x4)(ref inverse)).GetColumn(2)), Vector4.op_Implicit(((Matrix4x4)(ref inverse)).GetColumn(1))); } else { Matrix4x4 val3 = val2.parent.worldToLocalMatrix * val.localToWorldMatrix * inverse; localPosition = Vector4.op_Implicit(((Matrix4x4)(ref val3)).GetColumn(3)); localRotation = Quaternion.LookRotation(Vector4.op_Implicit(((Matrix4x4)(ref val3)).GetColumn(2)), Vector4.op_Implicit(((Matrix4x4)(ref val3)).GetColumn(1))); } val2.localPosition = localPosition; val2.localRotation = localRotation; } } public void SetupBonesAndMaterials() { //IL_0485: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skinnedMeshRenderer != (Object)null) { if (meshMaterials == null) { meshMaterials = Il2CppArrayBase<Material>.op_Implicit((Il2CppArrayBase<Material>)(object)((Renderer)skinnedMeshRenderer).sharedMaterials); } if (boneMudMeshes == null) { boneMudMeshes = new Dictionary<string, Transform>(); } boneChildren = ExtractValidBones(Il2CppArrayBase<Transform>.op_Implicit((Il2CppArrayBase<Transform>)(object)skinnedMeshRenderer.bones), baseMesh).ToList(); if (boneChildren != null) { if ((Object)(object)puppetMaster != (Object)null) { if (puppetBones == null) { puppetBones = puppetMaster.FindMatchingChildren(boneChildren); } if (puppetBones != null) { foreach (Transform puppetBone in puppetBones) { if ((Object)(object)puppetBone == (Object)null) { continue; } string name = ((Object)puppetBone).name; if (!boneMudMeshes.ContainsKey(name)) { Transform val = puppetBone.FindChildByKeyword("mudMesh"); if ((Object)(object)val != (Object)null) { boneMudMeshes[name] = val; } } } } } foreach (Transform boneChild in boneChildren) { if ((Object)(object)boneChild == (Object)null) { continue; } switch (((Object)boneChild).name) { case "head.x": if ((Object)(object)headBone == (Object)null) { headBone = boneChild; } break; case "root.x": if ((Object)(object)rootBone == (Object)null) { rootBone = boneChild; } break; case "spine_02.x": if ((Object)(object)spineBone == (Object)null) { spineBone = boneChild; } break; case "hand.r": if ((Object)(object)handBones.Item1 == (Object)null) { handBones.Item1 = boneChild; } break; case "hand.l": if ((Object)(object)handBones.Item2 == (Object)null) { handBones.Item2 = boneChild; } break; case "foot.l": if ((Object)(object)footBones.Item1 == (Object)null) { footBones.Item1 = boneChild; } break; case "foot.r": if ((Object)(object)footBones.Item2 == (Object)null) { footBones.Item2 = boneChild; } break; } } } } if (meshMaterials != null) { if ((Object)(object)hairMaterial == (Object)null) { hairMaterial = ((IEnumerable<Material>)meshMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => ((Object)m).name.Contains("Hair2_lux"))); } if ((Object)(object)suitMaterial == (Object)null) { suitMaterial = ((IEnumerable<Material>)meshMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => ((Object)m).name.Contains("NewSuit_Oct22"))); } if ((Object)(object)suitMaterial != (Object)null) { baseColor = suitMaterial.color; playerColor = baseColor; } } if ((Object)(object)headBone != (Object)null && (Object)(object)nateGlasses == (Object)null) { Transform val2 = headBone.FindChild("Nathan_Glasses"); if ((Object)(object)val2 != (Object)null) { nateGlasses = ((Component)val2).GetComponent<MeshRenderer>(); } } InitializeJawMasters(); } } public class LocalPlayer : BasePlayer { public static LocalPlayer Instance; public PlayerMovement playerMovement; public GameObject cinemachineBrainObj; public CinemachineBrain cinemachineBrain; public Material pmSuitMaterial; public bool lastJiminyState; public Grabable lastLeftHandItem; public Grabable lastRightHandItem; public Hat lastHat; private bool _sentInitialState = false; private float lastBoneSendTime = 0f; private const float boneSendInterval = 0.033f; private const int bytesPerBone = 29; private const int bonesPerPacket = 35; public BBSMicrophoneCapture mic; private bool micEnabled = false; private int micDevice = 0; public byte[] latestAudioFrame = null; private float _currentJawTarget = 0f; private bool _isSpeaking = false; private CameraCallback _onPreCullDelegate; private bool pushToTalkEnabled = false; private KeyCode pushToTalkKey = (KeyCode)118; public override void Initialize() { Core.DebugMsg("Starting LocalPlayer Initialize function"); baseObject = GameObject.Find("Dudest"); if ((Object)(object)baseObject == (Object)null) { Core.DebugMsg("Failed to find Dudest gO!"); } playerMovement = baseObject.GetComponent<PlayerMovement>(); if ((Object)(object)playerMovement == (Object)null) { Core.DebugMsg("Failed to find PlayerMovement component!"); } else { pmSuitMaterial = playerMovement.suitMat; } cinemachineBrainObj = GameObject.Find("BigManagerPrefab/Camera"); if ((Object)(object)cinemachineBrainObj == (Object)null) { Core.DebugMsg("Failed to find cinemachineBrainObj!"); } else { cinemachineBrain = cinemachineBrainObj.GetComponent<CinemachineBrain>(); } if ((Object)(object)cinemachineBrain == (Object)null) { Core.DebugMsg("Failed to find CinemachineBrain Component!"); } base.Initialize(); SetupBonesAndMaterials(); ApplySuitColor(); latestAudioFrame = new byte[0]; mic = new BBSMicrophoneCapture(); mic.Initialize(micDevice); if (micEnabled) { mic.StartRecording(); } SetPushToTalkEnabled(ModSettings.audio.PushToTalk.Value); _onPreCullDelegate = CameraCallback.op_Implicit((Action<Camera>)OnCameraPreCull); Camera.onPreCull += _onPreCullDelegate; Core.DebugMsg("LocalPlayer Initialized"); } public override void Dispose() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Delegate)(object)_onPreCullDelegate != (Delegate)null) { Camera.onPreCull -= _onPreCullDelegate; _onPreCullDelegate = null; } SetSuitColor(Color.white); ResetSuitColor(); if (mic != null) { mic.Dispose(); } mic = null; } private void OnCameraPreCull(Camera cam) { if (_isSpeaking) { SetMouthOpen(_currentJawTarget); } } private void UpdateMicrophone() { if (mic == null || !micEnabled) { return; } if (Core.networkManager == null || Core.networkManager.server == null) { if (mic.IsRecording()) { mic.StopRecording(); } } else if (!mic.IsRecording()) { mic.StartRecording(); } } public void SetMicrophoneEnabled(bool state) { micEnabled = state; if (state) { if (!mic.IsInitialized()) { mic.Initialize(micDevice); mic.StartRecording(); } else { mic.StartRecording(); } } else if (mic.IsInitialized()) { mic.StopRecording(); } } public bool IsMicrophoneEnabled() { return micEnabled; } public void SetPushToTalkEnabled(bool state) { pushToTalkEnabled = state; } public bool IsPushToTalkEnabled() { return pushToTalkEnabled; } public void SetPushToTalkKey(KeyCode key) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) pushToTalkKey = key; } public KeyCode GetPushToTalkKey() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) return pushToTalkKey; } public void SetMicrophoneDevice(int deviceIndex) { micDevice = deviceIndex; if (mic != null && mic.IsInitialized()) { bool flag = mic.IsRecording(); mic.Dispose(); mic = new BBSMicrophoneCapture(); mic.Initialize(micDevice); if (flag) { mic.StartRecording(); } } } public int GetMicrophoneDevice() { return micDevice; } public GameObject GetCameraObject() { if ((Object)(object)cinemachineBrain == (Object)null) { return null; } ICinemachineCamera activeVirtualCamera = cinemachineBrain.ActiveVirtualCamera; if (activeVirtualCamera == null) { return null; } GameObject virtualCameraGameObject = activeVirtualCamera.VirtualCameraGameObject; if ((Object)(object)virtualCameraGameObject == (Object)null) { return null; } return virtualCameraGameObject; } public void ApplySuitColor() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) Color value = ModSettings.player.SuitColor.Value; if (value.a != 1f) { value.a = 1f; } SetSuitColor(value); } public override void SetSuitColor(Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) base.SetSuitColor(color); if ((Object)(object)pmSuitMaterial != (Object)null && pmSuitMaterial.color != playerColor) { pmSuitMaterial.color = playerColor; } } public void CleanCompletely() { if (!((Object)(object)playerMovement == (Object)null)) { playerMovement.CleanPlayerCompletely(); } } public override void Update() { UpdateMicrophone(); if (Core.networkManager.server == null || (Object)(object)playerMovement == (Object)null) { return; } if (!_sentInitialState) { Hat currentHat = playerMovement.currentHat; if ((Object)(object)currentHat != (Object)null) { Core.networkManager.SendDonHat(currentHat); } lastHat = currentHat; Grabable val = ((Il2CppArrayBase<Grabable>)(object)playerMovement.handItems)[0]; Grabable val2 = (lastLeftHandItem = ((Il2CppArrayBase<Grabable>)(object)playerMovement.handItems)[1]); lastRightHandItem = val; if ((Object)(object)val != (Object)null) { Core.networkManager.SendHoldGrabable(val, 0); } if ((Object)(object)val2 != (Object)null) { Core.networkManager.SendHoldGrabable(val2, 1); } Core.networkManager.SendJiminyRibbonState(lastJiminyState); Core.networkManager.SendCollisionToggle(ModSettings.player.Collisions.Value); _sentInitialState = true; return; } if ((Object)(object)jiminyRibbon == (Object)null) { lastJiminyState = false; } else if (lastJiminyState != jiminyRibbon.active) { lastJiminyState = jiminyRibbon.active; Core.networkManager.SendJiminyRibbonState(lastJiminyState); } Grabable val3 = ((Il2CppArrayBase<Grabable>)(object)playerMovement.handItems)[1]; Grabable val4 = ((Il2CppArrayBase<Grabable>)(object)playerMovement.handItems)[0]; if ((Object)(object)lastLeftHandItem != (Object)(object)val3) { lastLeftHandItem = val3; if ((Object)(object)val3 != (Object)null) { Core.DebugMsg("Left Hand Pickup!"); Core.networkManager.SendHoldGrabable(val3, 1); } else { Core.DebugMsg("Left Hand Drop!"); Core.networkManager.SendDropGrabable(1); } } if ((Object)(object)lastRightHandItem != (Object)(object)val4) { lastRightHandItem = val4; if ((Object)(object)val4 != (Object)null) { Core.DebugMsg("Right Hand Pickup!"); Core.networkManager.SendHoldGrabable(val4, 0); } else { Core.DebugMsg("Right Hand Drop!"); Core.networkManager.SendDropGrabable(0); } } Hat currentHat2 = playerMovement.currentHat; if ((Object)(object)lastHat != (Object)(object)currentHat2) { lastHat = currentHat2; if ((Object)(object)currentHat2 != (Object)null) { Core.DebugMsg("Hat Don!"); Core.networkManager.SendDonHat(currentHat2); } else { Core.DebugMsg("Hat Doff!"); Core.networkManager.SendDoffHat(); } } } public override void LateUpdate() { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) if (!_sentInitialState || Core.networkManager.server == null || (Object)(object)playerMovement == (Object)null || boneChildren == null) { return; } if (IsMicrophoneEnabled() != ModSettings.audio.MicrophoneEnabled.Value) { SetMicrophoneEnabled(ModSettings.audio.MicrophoneEnabled.Value); } if (GetMicrophoneDevice() != ModSettings.audio.SelectedMicrophoneIndex.Value) { SetMicrophoneDevice(ModSettings.audio.SelectedMicrophoneIndex.Value); } if (micEnabled && mic != null && mic.IsRecording()) { bool flag = true; if (pushToTalkEnabled) { flag = Input.GetKey(pushToTalkKey); } if (flag) { latestAudioFrame = mic.GetOpusPacket(); if (latestAudioFrame != null && latestAudioFrame.Length != 0) { Core.networkManager.SendAudioFrame(latestAudioFrame); _currentJawTarget = mic.GetAmplitude(); _isSpeaking = true; SetMouthOpen(_currentJawTarget); } else { _isSpeaking = false; } } else { _isSpeaking = false; } } else { _isSpeaking = false; } if (!(Time.realtimeSinceStartup - lastBoneSendTime < 0.033f)) { lastBoneSendTime = Time.realtimeSinceStartup; TransformNet[] bones = TransformNet.ToNet(boneChildren); Core.networkManager.SendBones(bones, 0); } } } public class NameTagUI { public GameObject baseObject; public TextMeshPro textMeshPro; public Vector3 positionOffset = new Vector3(0f, 0.5f, 0f); public NameTagUI(Transform parent) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) baseObject = new GameObject("Nametag"); SetParent(parent); textMeshPro = baseObject.AddComponent<TextMeshPro>(); ((TMP_Text)textMeshPro).alignment = (TextAlignmentOptions)514; ((TMP_Text)textMeshPro).fontSize = 1.5f; Shader val = Shader.Find("TextMeshPro/Distance Field Overlay"); if ((Object)(object)val != (Object)null) { Material val2 = new Material(val); val2.mainTexture = ((TMP_Asset)((TMP_Text)textMeshPro).font).material.mainTexture; ((TMP_Text)textMeshPro).fontMaterial = val2; } else { Core.logger.Warning("Could not find TMP Distance Field Overlay shader!"); } SetColor(Color.white); SetText("Nate"); } public void Destroy() { if ((Object)(object)baseObject != (Object)null) { Object.Destroy((Object)(object)baseObject); } } public void LateUpdate() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)baseObject == (Object)null) && LocalPlayer.Instance != null) { GameObject cameraObject = LocalPlayer.Instance.GetCameraObject(); if ((Object)(object)cameraObject != (Object)null) { float num = Vector3.Distance(cameraObject.transform.position, baseObject.transform.position); SetActive(num <= 100f); RotateTowardsCamera(cameraObject.transform.position); } } } public void SetActive(bool active) { if (!((Object)(object)baseObject == (Object)null) && baseObject.active != active) { baseObject.active = active; } } public void SetParent(Transform parent) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)baseObject == (Object)null) { return; } baseObject.transform.SetParent(parent, false); baseObject.transform.localPosition = positionOffset; if (LocalPlayer.Instance != null) { GameObject cameraObject = LocalPlayer.Instance.GetCameraObject(); if ((Object)(object)cameraObject != (Object)null) { RotateTowardsCamera(cameraObject.transform.position); } } } public void SetText(string text) { if (!((Object)(object)textMeshPro == (Object)null) && !(((TMP_Text)textMeshPro).text == text)) { ((TMP_Text)textMeshPro).text = text; ((Graphic)textMeshPro).SetAllDirty(); } } public void SetColor(Color color) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) if (!((Object)(object)textMeshPro == (Object)null) && !(((Graphic)textMeshPro).color == color)) { ((Graphic)textMeshPro).color = color; ((Graphic)textMeshPro).SetAllDirty(); } } public Color GetColor() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)textMeshPro == (Object)null) { return default(Color); } return ((Graphic)textMeshPro).color; } private void RotateTowardsCamera(Vector3 cameraPosition) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)baseObject == (Object)null) && baseObject.activeSelf) { baseObject.transform.rotation = Quaternion.LookRotation(baseObject.transform.position - cameraPosition); } } } public class RemotePlayer : BasePlayer { [CompilerGenerated] private sealed class <DelayedComponentStrip>d__33 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Transform mesh; private IEnumerator<Component> <>s__1; private Component <component>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedComponentStrip>d__33(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = null; <component>5__2 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)mesh != (Object)null) { <>s__1 = ((Component)mesh).GetComponents<Component>().GetEnumerator(); try { while (<>s__1.MoveNext()) { <component>5__2 = <>s__1.Current; if (!(<component>5__2 is Transform)) { Object.Destroy((Object)(object)<component>5__2); } <component>5__2 = null; } } finally { if (<>s__1 != null) { <>s__1.Dispose(); } } <>s__1 = null; } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedGazableFillin>d__24 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Gazable _gazable; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedGazableFillin>d__24(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; _gazable.wontMove = false; _gazable.sqrRad = 5f; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedSpecificComponentStrip>d__34<T> : IEnumerator<object>, IEnumerator, IDisposable where T : Component { private int <>1__state; private object <>2__current; public Transform bone; private Il2CppArrayBase<T> <components>5__1; private IEnumerator<T> <>s__2; private T <c>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedSpecificComponentStrip>d__34(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <components>5__1 = null; <>s__2 = null; <c>5__3 = default(T); <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)bone != (Object)null) { <components>5__1 = ((Component)bone).GetComponentsInChildren<T>(true); if (<components>5__1 != null) { <>s__2 = <components>5__1.GetEnumerator(); try { while (<>s__2.MoveNext()) { <c>5__3 = <>s__2.Current; if ((Object)(object)<c>5__3 != (Object)null) { Object.Destroy((Object)(object)<c>5__3); } <c>5__3 = default(T); } } finally { if (<>s__2 != null) { <>s__2.Dispose(); } } <>s__2 = null; } <components>5__1 = null; } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <EnableCollisionCoroutine>d__36 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public RemotePlayer <>4__this; private Dictionary<string, (Rigidbody, CapsuleCollider)>.ValueCollection.Enumerator <>s__1; private (Rigidbody, CapsuleCollider) <val>5__2; private Collider[] <>s__3; private int <>s__4; private Collider <val>5__5; private Collider[] <>s__6; private int <>s__7; private Collider <val>5__8; private Collider[] <>s__9; private int <>s__10; private Collider <val>5__11; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnableCollisionCoroutine>d__36(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = default(Dictionary<string, (Rigidbody, CapsuleCollider)>.ValueCollection.Enumerator); <val>5__2 = default((Rigidbody, CapsuleCollider)); <>s__3 = null; <val>5__5 = null; <>s__6 = null; <val>5__8 = null; <>s__9 = null; <val>5__11 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; goto IL_0044; case 1: <>1__state = -1; goto IL_0044; case 2: { <>1__state = -1; break; } IL_0044: if (!<>4__this.firstBoneInterpRan) { <>2__current = null; <>1__state = 1; return true; } break; } if (<>4__this.distanceFromPlayer <= 0.6f) { <>2__current = null; <>1__state = 2; return true; } if (<>4__this.boneColliders != null) { <>s__1 = <>4__this.boneColliders.Values.GetEnumerator(); try { while (<>s__1.MoveNext()) { <val>5__2 = <>s__1.Current; if (!((Object)(object)<val>5__2.Item2 == (Object)null)) { ((Collider)<val>5__2.Item2).enabled = true; <val>5__2 = default((Rigidbody, CapsuleCollider)); } } } finally { ((IDisposable)<>s__1).Dispose(); } <>s__1 = default(Dictionary<string, (Rigidbody, CapsuleCollider)>.ValueCollection.Enumerator); } if (<>4__this.hatColliders != null) { <>s__3 = <>4__this.hatColliders; for (<>s__4 = 0; <>s__4 < <>s__3.Length; <>s__4++) { <val>5__5 = <>s__3[<>s__4]; if (!((Object)(object)<val>5__5 == (Object)null)) { <val>5__5.enabled = true; <val>5__5 = null; } } <>s__3 = null; } if (<>4__this.heldItemColliders.Item1 != null) { <>s__6 = <>4__this.heldItemColliders.Item1; for (<>s__7 = 0; <>s__7 < <>s__6.Length; <>s__7++) { <val>5__8 = <>s__6[<>s__7]; if (!((Object)(object)<val>5__8 == (Object)null)) { <val>5__8.enabled = true; <val>5__8 = null; } } <>s__6 = null; } if (<>4__this.heldItemColliders.Item2 != null) { <>s__9 = <>4__this.heldItemColliders.Item2; for (<>s__10 = 0; <>s__10 < <>s__9.Length; <>s__10++) { <val>5__11 = <>s__9[<>s__10]; if (!((Object)(object)<val>5__11 == (Object)null)) { <val>5__11.enabled = true; <val>5__11 = null; } } <>s__9 = null; } <>4__this.collisionCoroutineToken = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static ConcurrentBag<RemotePlayer> GlobalPool = new ConcurrentBag<RemotePlayer>(); private static Dictionary<string, GameObject> savablePrefabs = new Dictionary<string, GameObject>(); public static Texture2D suitTexture; public NameTagUI nameTag; public Gazable gazable; public Dictionary<string, (Rigidbody, CapsuleCollider)> boneColliders; public Dictionary<Transform, Transform> boneCrushers; public Hat hat; public Collider[] hatColliders; public BBSAudioSource audioSource; public (Grabable, Grabable) heldItems; public (Collider[], Collider[]) heldItemColliders; public (FootData, FootData) feetData; public string displayName = "Nate"; private BoneSnapshot currentBoneGroup; private ConcurrentQueue<BoneSnapshot> snapshotBuffer = new ConcurrentQueue<BoneSnapshot>(); private const double INTERPDELAY = 0.1; public bool netCollisionsEnabled; private bool firstBoneInterpRan; private object collisionCoroutineToken; public float distanceFromPlayer; public bool firstAppearanceApplication; public static readonly Dictionary<string, (Vector3 center, float radius, float height, int direction)> colliderTemplate = new Dictionary<string, (Vector3, float, float, int)> { { "head.x", (new Vector3(0f, 0.1f, 0.05f), 0.13f, 0.35f, 1) }, { "spine_02.x", (new Vector3(0f, 0.21f, 0f), 0.15f, 0.42f, 0) }, { "spine_01.x", (new Vector3(0f, 0.1f, 0f), 0.1636f, 0.45f, 0) }, { "root.x", (new Vector3(0f, 0f, -0.025f), 0.175f, 0.5f, 0) }, { "arm_stretch.l", (new Vector3(0f, 0.13f, 0f), 0.07f, 0.38f, 1) }, { "forearm_stretch.l", (new Vector3(0f, 0.15f, 0f), 0.05f, 0.35f, 1) }, { "hand.l", (new Vector3(0f, 0.07f, 0f), 0.05f, 0.2f, 1) }, { "arm_stretch.r", (new Vector3(0f, 0.13f, 0f), 0.07f, 0.38f, 1) }, { "forearm_stretch.r", (new Vector3(0f, 0.15f, 0f), 0.05f, 0.35f, 1) }, { "hand.r", (new Vector3(0f, 0.07f, 0f), 0.05f, 0.2f, 1) }, { "thigh_stretch.l", (new Vector3(0.01f, 0.15f, 0f), 0.121f, 0.6f, 1) }, { "leg_stretch.l", (new Vector3(0f, 0.15f, 0f), 0.075f, 0.455f, 1) }, { "foot.l", (new Vector3(0f, 0.1f, -0.02f), 0.06f, 0.3f, 1) }, { "thigh_stretch.r", (new Vector3(0.01f, 0.15f, 0f), 0.121f, 0.6f, 1) }, { "leg_stretch.r", (new Vector3(0f, 0.15f, 0f), 0.075f, 0.455f, 1) }, { "foot.r", (new Vector3(0f, 0.1f, -0.02f), 0.06f, 0.3f, 1) } }; public void Initialize(int numClones) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) if (LocalPlayer.Instance == null) { return; } if ((Object)(object)suitTexture == (Object)null) { LocalPlayer.Instance.CleanCompletely(); suitTexture = LocalPlayer.Instance.CloneSuitTexture(); } baseObject = new GameObject($"NateClone{numClones}"); nameTag = new NameTagUI(baseObject.transform); if ((Object)(object)LocalPlayer.Instance.baseMesh != (Object)null) { baseMesh = Object.Instantiate<Transform>(LocalPlayer.Instance.baseMesh); ((Object)baseMesh).name = "NateMesh"; baseMesh.parent = baseObject.transform; ((Component)baseMesh).transform.position = Vector3.zero; MelonCoroutines.Start(DelayedComponentStrip(baseMesh)); } if ((Object)(object)LocalPlayer.Instance.particleCrushers != (Object)null) { particleCrushers = Object.Instantiate<Transform>(LocalPlayer.Instance.particleCrushers); particleCrushers.parent = baseObject.transform; } Initialize(); if ((
Mods/Concentus.dll
Decompiled 13 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using Concentus.Celt; using Concentus.Celt.Structs; using Concentus.Common; using Concentus.Common.CPlusPlus; using Concentus.Enums; using Concentus.Native; using Concentus.Silk; using Concentus.Silk.Enums; using Concentus.Silk.Structs; using Concentus.Structs; using Microsoft.CodeAnalysis; using Microsoft.Win32.SafeHandles; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("ParityTest, PublicKey=002400000480000094000000060200000024000052534131000400000100010071a2f675c04c87e64b9be6d37f5833c5285fb4ed883780cf6d61e80aee5d77950b2f06dd45bc634f53405f2a2b7b2332f4dfdcb0554ffc97b935e7343e76e733eea44346e56ac1098c12a66de71e324f2f503f9f2e32560910e2082d6943df50db42679a330e52979bd1eefbb59485d2c7420d158f6ab6d41bdf42d2172675e1")] [assembly: InternalsVisibleTo("TestOpusEncode, PublicKey=002400000480000094000000060200000024000052534131000400000100010071a2f675c04c87e64b9be6d37f5833c5285fb4ed883780cf6d61e80aee5d77950b2f06dd45bc634f53405f2a2b7b2332f4dfdcb0554ffc97b935e7343e76e733eea44346e56ac1098c12a66de71e324f2f503f9f2e32560910e2082d6943df50db42679a330e52979bd1eefbb59485d2c7420d158f6ab6d41bdf42d2172675e1")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Logan Stromberg")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("© Xiph.Org Foundation, Skype Limited, CSIRO, Microsoft Corp.")] [assembly: AssemblyDescription("This package is a portable C# implementation of the Opus audio compression codec (see https://opus-codec.org/ for more details). This package contains the Opus encoder, decoder, multistream codecs, repacketizer, as well as a port of the libspeexdsp resampler. It does NOT contain code to parse .ogg or .opus container files or to manage RTP packet streams. For better performance depending on your platform, see also the Concentus.Native package.")] [assembly: AssemblyFileVersion("2.2.2.0")] [assembly: AssemblyInformationalVersion("2.2.2+6c2328dc19044601e33a9c11628b8d60e1f3011c")] [assembly: AssemblyProduct("Concentus")] [assembly: AssemblyTitle("Concentus")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/lostromb/concentus")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.2.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } } namespace Concentus { public interface IOpusDecoder : IDisposable { OpusBandwidth Bandwidth { get; } uint FinalRange { get; } int Gain { get; set; } int LastPacketDuration { get; } int NumChannels { get; } int Pitch { get; } int SampleRate { get; } int Decode(ReadOnlySpan<byte> in_data, Span<float> out_pcm, int frame_size, bool decode_fec = false); int Decode(ReadOnlySpan<byte> in_data, Span<short> out_pcm, int frame_size, bool decode_fec = false); void ResetState(); string GetVersionString(); } public interface IOpusEncoder : IDisposable { OpusApplication Application { get; set; } int Bitrate { get; set; } int ForceChannels { get; set; } OpusBandwidth MaxBandwidth { get; set; } OpusBandwidth Bandwidth { get; set; } bool UseDTX { get; set; } int Complexity { get; set; } bool UseInbandFEC { get; set; } int PacketLossPercent { get; set; } bool UseVBR { get; set; } bool UseConstrainedVBR { get; set; } OpusSignal SignalType { get; set; } int Lookahead { get; } int SampleRate { get; } int NumChannels { get; } uint FinalRange { get; } int LSBDepth { get; set; } OpusFramesize ExpertFrameDuration { get; set; } OpusMode ForceMode { set; } bool PredictionDisabled { get; set; } int Encode(ReadOnlySpan<short> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); int Encode(ReadOnlySpan<float> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); void ResetState(); string GetVersionString(); } public interface IOpusMultiStreamDecoder : IDisposable { OpusBandwidth Bandwidth { get; } uint FinalRange { get; } int Gain { get; set; } int LastPacketDuration { get; } int SampleRate { get; } int NumChannels { get; } int DecodeMultistream(ReadOnlySpan<byte> data, Span<float> out_pcm, int frame_size, bool decode_fec); int DecodeMultistream(ReadOnlySpan<byte> data, Span<short> out_pcm, int frame_size, bool decode_fec); void ResetState(); string GetVersionString(); } public interface IOpusMultiStreamEncoder : IDisposable { OpusApplication Application { get; set; } OpusBandwidth Bandwidth { get; set; } int Bitrate { get; set; } int Complexity { get; set; } int NumChannels { get; } OpusFramesize ExpertFrameDuration { get; set; } uint FinalRange { get; } OpusMode ForceMode { set; } int Lookahead { get; } int LSBDepth { get; set; } OpusBandwidth MaxBandwidth { get; set; } int PacketLossPercent { get; set; } bool PredictionDisabled { get; set; } int SampleRate { get; } OpusSignal SignalType { get; set; } bool UseConstrainedVBR { get; set; } bool UseDTX { get; set; } bool UseInbandFEC { get; set; } bool UseVBR { get; set; } int EncodeMultistream(ReadOnlySpan<float> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); int EncodeMultistream(ReadOnlySpan<short> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); void ResetState(); string GetVersionString(); } public interface IResampler : IDisposable { int InputLatency { get; } int InputStride { get; set; } int OutputLatencySamples { get; } TimeSpan OutputLatency { get; } int OutputStride { get; set; } int Quality { get; set; } void GetRateFraction(out int ratio_num, out int ratio_den); void GetRates(out int in_rate, out int out_rate); void ResetMem(); void SkipZeroes(); void Process(int channel_index, Span<float> input, ref int in_len, Span<float> output, ref int out_len); void Process(int channel_index, Span<short> input, ref int in_len, Span<short> output, ref int out_len); void ProcessInterleaved(Span<float> input, ref int in_len, Span<float> output, ref int out_len); void ProcessInterleaved(Span<short> input, ref int in_len, Span<short> output, ref int out_len); void SetRateFraction(int ratio_num, int ratio_den, int in_rate, int out_rate); void SetRates(int in_rate, int out_rate); } public static class OpusCodecFactory { private static readonly object _mutex = new object(); private static bool _nativeLibInitialized = false; private static bool _isNativeLibAvailable = false; private static bool _userAllowNativeLib = true; public static bool AttemptToUseNativeLibrary { get { return _userAllowNativeLib; } set { _userAllowNativeLib = value; } } public static IOpusEncoder CreateEncoder(int sampleRate, int numChannels, OpusApplication application = OpusApplication.OPUS_APPLICATION_AUDIO, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusEncoder.Create(sampleRate, numChannels, application); } return new OpusEncoder(sampleRate, numChannels, application); } public static IOpusDecoder CreateDecoder(int sampleRate, int numChannels, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusDecoder.Create(sampleRate, numChannels); } return new OpusDecoder(sampleRate, numChannels); } public static IOpusMultiStreamEncoder CreateMultiStreamEncoder(int sampleRate, int numChannels, int mappingFamily, out int streams, out int coupledStreams, byte[] mapping, OpusApplication application, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusMultistreamEncoder.Create(sampleRate, numChannels, mappingFamily, out streams, out coupledStreams, mapping, application); } return OpusMSEncoder.CreateSurround(sampleRate, numChannels, mappingFamily, out streams, out coupledStreams, mapping, application); } public static IOpusMultiStreamDecoder CreateMultiStreamDecoder(int sampleRate, int numChannels, int streams, int coupledStreams, byte[] mapping, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusMultistreamDecoder.Create(sampleRate, numChannels, streams, coupledStreams, mapping); } return new OpusMSDecoder(sampleRate, numChannels, streams, coupledStreams, mapping); } private static bool NativeLibraryAvailable(TextWriter messageLogger) { lock (_mutex) { if (!_nativeLibInitialized) { try { _isNativeLibAvailable = NativeOpus.Initialize(messageLogger); messageLogger?.WriteLine($"Is native opus available? {_isNativeLibAvailable}"); } catch (Exception ex) { messageLogger?.WriteLine(ex.ToString()); } _nativeLibInitialized = true; } return _isNativeLibAvailable; } } } internal static class Analysis { private const double M_PI = 3.141592653; private const float cA = 0.43157974f; private const float cB = 0.678484f; private const float cC = 0.08595542f; private const float cE = MathF.PI / 2f; private const int NB_TONAL_SKIP_BANDS = 9; internal static float fast_atan2f(float y, float x) { if (Inlines.ABS16(x) + Inlines.ABS16(y) < 1E-09f) { x *= 1E+12f; y *= 1E+12f; } float num = x * x; float num2 = y * y; if (num < num2) { float num3 = (num2 + 0.678484f * num) * (num2 + 0.08595542f * num); if (num3 != 0f) { return (0f - x) * y * (num2 + 0.43157974f * num) / num3 + ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)); } if (!(y < 0f)) { return MathF.PI / 2f; } return -MathF.PI / 2f; } float num4 = (num + 0.678484f * num2) * (num + 0.08595542f * num2); if (num4 != 0f) { return x * y * (num + 0.43157974f * num2) / num4 + ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)) - ((x * y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)); } return ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)) - ((x * y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)); } internal static void tonality_analysis_init(TonalityAnalysisState tonal) { tonal.Reset(); } internal static void tonality_get_info(TonalityAnalysisState tonal, AnalysisInfo info_out, int len) { int num = tonal.read_pos; int num2 = tonal.write_pos - tonal.read_pos; if (num2 < 0) { num2 += 200; } if (len > 480 && num != tonal.write_pos) { num++; if (num == 200) { num = 0; } } if (num == tonal.write_pos) { num--; } if (num < 0) { num = 199; } info_out.Assign(tonal.info[num]); tonal.read_subframe += len / 120; while (tonal.read_subframe >= 4) { tonal.read_subframe -= 4; tonal.read_pos++; } if (tonal.read_pos >= 200) { tonal.read_pos -= 200; } num2 = Inlines.IMAX(num2 - 10, 0); float num3 = 0f; int i; for (i = 0; i < 200 - num2; i++) { num3 += tonal.pmusic[i]; } for (; i < 200; i++) { num3 += tonal.pspeech[i]; } num3 = num3 * tonal.music_confidence + (1f - num3) * tonal.speech_confidence; info_out.music_prob = num3; } internal static void tonality_analysis<T>(TonalityAnalysisState tonal, CeltMode celt_mode, ReadOnlySpan<T> x, int len, int offset, int c1, int c2, int C, int lsb_depth, Downmix.downmix_func<T> downmix) { int num = 480; int num2 = 240; float[] angle = tonal.angle; float[] d_angle = tonal.d_angle; float[] d2_angle = tonal.d2_angle; float[] array = new float[18]; float[] array2 = new float[18]; float[] array3 = new float[8]; float[] array4 = new float[25]; float num3 = 97.40909f; float num4 = 0f; float[] array5 = new float[2]; int num5 = 0; float num6 = 0f; tonal.last_transition++; float num7 = 1f / (float)Inlines.IMIN(20, 1 + tonal.count); float num8 = 1f / (float)Inlines.IMIN(50, 1 + tonal.count); float num9 = 1f / (float)Inlines.IMIN(1000, 1 + tonal.count); if (tonal.count < 4) { tonal.music_prob = 0.5f; } FFTState st = celt_mode.mdct.kfft[0]; if (tonal.count == 0) { tonal.mem_fill = 240; } downmix(x, tonal.inmem, tonal.mem_fill, Inlines.IMIN(len, 720 - tonal.mem_fill), offset, c1, c2, C); if (tonal.mem_fill + len < 720) { tonal.mem_fill += len; return; } AnalysisInfo analysisInfo = tonal.info[tonal.write_pos++]; if (tonal.write_pos >= 200) { tonal.write_pos -= 200; } int[] array6 = new int[960]; int[] array7 = new int[960]; float[] array8 = new float[240]; float[] array9 = new float[240]; for (int i = 0; i < num2; i++) { float num10 = Tables.analysis_window[i]; array6[2 * i] = (int)(num10 * (float)tonal.inmem[i]); array6[2 * i + 1] = (int)(num10 * (float)tonal.inmem[num2 + i]); array6[2 * (num - i - 1)] = (int)(num10 * (float)tonal.inmem[num - i - 1]); array6[2 * (num - i - 1) + 1] = (int)(num10 * (float)tonal.inmem[num + num2 - i - 1]); } Arrays.MemMoveInt(tonal.inmem, 480, 0, 240); int num11 = len - (720 - tonal.mem_fill); downmix(x, tonal.inmem, 240, num11, offset + 720 - tonal.mem_fill, c1, c2, C); tonal.mem_fill = 240 + num11; KissFFT.opus_fft(st, array6, array7); for (int i = 1; i < num2; i++) { float x2 = (float)array7[2 * i] + (float)array7[2 * (num - i)]; float y = (float)array7[2 * i + 1] - (float)array7[2 * (num - i) + 1]; float x3 = (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1]; float y2 = (float)array7[2 * (num - i)] - (float)array7[2 * i]; float num12 = 1f / (2f * MathF.PI) * fast_atan2f(y, x2); float num13 = num12 - angle[i]; float num14 = num13 - d_angle[i]; float num15 = 1f / (2f * MathF.PI) * fast_atan2f(y2, x3); float num16 = num15 - num12; float num17 = num16 - num13; float num18 = num14 - (float)Math.Floor(0.5f + num14); array9[i] = Inlines.ABS16(num18); num18 *= num18; num18 *= num18; float num19 = num17 - (float)Math.Floor(0.5f + num17); array9[i] += Inlines.ABS16(num19); num19 *= num19; num19 *= num19; float num20 = 0.25f * (d2_angle[i] + 2f * num18 + num19); array8[i] = 1f / (1f + 640f * num3 * num20) - 0.015f; angle[i] = num15; d_angle[i] = num16; d2_angle[i] = num19; } float num21 = 0f; float num22 = 0f; analysisInfo.activity = 0f; float num23 = 0f; float num24 = 0f; if (tonal.count == 0) { for (int j = 0; j < 18; j++) { tonal.lowE[j] = 1E+10f; tonal.highE[j] = -1E+10f; } } float num25 = 0f; float num26 = 0f; for (int j = 0; j < 18; j++) { float num27 = 0f; float num28 = 0f; float num29 = 0f; for (int i = Tables.tbands[j]; i < Tables.tbands[j + 1]; i++) { float num30 = (float)array7[2 * i] * (float)array7[2 * i] + (float)array7[2 * (num - i)] * (float)array7[2 * (num - i)] + (float)array7[2 * i + 1] * (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1] * (float)array7[2 * (num - i) + 1]; num30 *= 5.55E-17f; num27 += num30; num28 += num30 * array8[i]; num29 += num30 * 2f * (0.5f - array9[i]); } tonal.E[tonal.E_count][j] = num27; num23 += num29 / (1E-15f + num27); num26 += (float)Math.Sqrt(num27 + 1E-10f); array2[j] = (float)Math.Log(num27 + 1E-10f); tonal.lowE[j] = Inlines.MIN32(array2[j], tonal.lowE[j] + 0.01f); tonal.highE[j] = Inlines.MAX32(array2[j], tonal.highE[j] - 0.1f); if (tonal.highE[j] < tonal.lowE[j] + 1f) { tonal.highE[j] += 0.5f; tonal.lowE[j] -= 0.5f; } num25 += (array2[j] - tonal.lowE[j]) / (1E-15f + tonal.highE[j] - tonal.lowE[j]); float num31; float num32 = (num31 = 0f); for (int i = 0; i < 8; i++) { num32 += (float)Math.Sqrt(tonal.E[i][j]); num31 += tonal.E[i][j]; } float num33 = Inlines.MIN16(0.99f, num32 / (float)Math.Sqrt(1E-15 + (double)(8f * num31))); num33 *= num33; num33 *= num33; num24 += num33; array[j] = Inlines.MAX16(num28 / (1E-15f + num27), num33 * tonal.prev_band_tonality[j]); num21 += array[j]; if (j >= 9) { num21 -= array[j - 18 + 9]; } num22 = Inlines.MAX16(num22, (1f + 0.03f * (float)(j - 18)) * num21); num4 += array[j] * (float)(j - 8); tonal.prev_band_tonality[j] = array[j]; } float num34 = 0f; num5 = 0; num6 = 0f; float num35 = 0.00057f / (float)(1 << Inlines.IMAX(0, lsb_depth - 8)); num35 *= 134217730f; num35 *= num35; for (int j = 0; j < 21; j++) { float num36 = 0f; int num37 = Tables.extra_bands[j]; int num38 = Tables.extra_bands[j + 1]; for (int i = num37; i < num38; i++) { float num39 = (float)array7[2 * i] * (float)array7[2 * i] + (float)array7[2 * (num - i)] * (float)array7[2 * (num - i)] + (float)array7[2 * i + 1] * (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1] * (float)array7[2 * (num - i) + 1]; num36 += num39; } num6 = Inlines.MAX32(num6, num36); tonal.meanE[j] = Inlines.MAX32((1f - num9) * tonal.meanE[j], num36); num36 = Inlines.MAX32(num36, tonal.meanE[j]); num34 = Inlines.MAX32(0.05f * num34, num36); if ((double)num36 > 0.1 * (double)num34 && num36 * 1E+09f > num6 && num36 > num35 * (float)(num38 - num37)) { num5 = j; } } if (tonal.count <= 2) { num5 = 20; } num26 = 20f * (float)Math.Log10(num26); tonal.Etracker = Inlines.MAX32(tonal.Etracker - 0.03f, num26); tonal.lowECount *= 1f - num8; if (num26 < tonal.Etracker - 30f) { tonal.lowECount += num8; } for (int i = 0; i < 8; i++) { float num40 = 0f; for (int j = 0; j < 16; j++) { num40 += Tables.dct_table[i * 16 + j] * array2[j]; } array3[i] = num40; } num24 /= 18f; num25 /= 18f; if (tonal.count < 10) { num25 = 0.5f; } num23 /= 18f; analysisInfo.activity = num23 + (1f - num23) * num25; num21 = num22 / 9f; num21 = (tonal.prev_tonality = Inlines.MAX16(num21, tonal.prev_tonality * 0.8f)); num4 /= 64f; analysisInfo.tonality_slope = num4; tonal.E_count = (tonal.E_count + 1) % 8; tonal.count++; analysisInfo.tonality = num21; for (int i = 0; i < 4; i++) { array4[i] = -0.12299f * (array3[i] + tonal.mem[i + 24]) + 0.49195f * (tonal.mem[i] + tonal.mem[i + 16]) + 0.69693f * tonal.mem[i + 8] - 1.4349f * tonal.cmean[i]; } for (int i = 0; i < 4; i++) { tonal.cmean[i] = (1f - num7) * tonal.cmean[i] + num7 * array3[i]; } for (int i = 0; i < 4; i++) { array4[4 + i] = 0.63246f * (array3[i] - tonal.mem[i + 24]) + 0.31623f * (tonal.mem[i] - tonal.mem[i + 16]); } for (int i = 0; i < 3; i++) { array4[8 + i] = 0.53452f * (array3[i] + tonal.mem[i + 24]) - 0.26726f * (tonal.mem[i] + tonal.mem[i + 16]) - 0.53452f * tonal.mem[i + 8]; } if (tonal.count > 5) { for (int i = 0; i < 9; i++) { tonal.std[i] = (1f - num7) * tonal.std[i] + num7 * array4[i] * array4[i]; } } for (int i = 0; i < 8; i++) { tonal.mem[i + 24] = tonal.mem[i + 16]; tonal.mem[i + 16] = tonal.mem[i + 8]; tonal.mem[i + 8] = tonal.mem[i]; tonal.mem[i] = array3[i]; } for (int i = 0; i < 9; i++) { array4[11 + i] = (float)Math.Sqrt(tonal.std[i]); } array4[20] = analysisInfo.tonality; array4[21] = analysisInfo.activity; array4[22] = num24; array4[23] = analysisInfo.tonality_slope; array4[24] = tonal.lowECount; MultiLayerPerceptron.mlp_process(Tables.net, array4, array5); array5[0] = 0.5f * (array5[0] + 1f); array5[0] = 0.01f + 1.21f * array5[0] * array5[0] - 0.23f * (float)Math.Pow(array5[0], 10.0); array5[1] = 0.5f * array5[1] + 0.5f; array5[0] = array5[1] * array5[0] + (1f - array5[1]) * 0.5f; float num41 = 5E-05f * array5[1]; float num42 = 0.05f; float num43 = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, array5[0])); float num44 = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, tonal.music_prob)); num42 = 0.01f + 0.05f * Inlines.ABS16(num43 - num44) / (num43 * (1f - num44) + num44 * (1f - num43)); float num45 = (1f - tonal.music_prob) * (1f - num41) + tonal.music_prob * num41; float num46 = tonal.music_prob * (1f - num41) + (1f - tonal.music_prob) * num41; num45 *= (float)Math.Pow(1f - array5[0], num42); num46 *= (float)Math.Pow(array5[0], num42); tonal.music_prob = num46 / (num45 + num46); analysisInfo.music_prob = tonal.music_prob; float num47 = 1E-20f; float num48 = (float)Math.Pow(1f - array5[0], num42); float num49 = (float)Math.Pow(array5[0], num42); if (tonal.count == 1) { tonal.pspeech[0] = 0.5f; tonal.pmusic[0] = 0.5f; } float num50 = tonal.pspeech[0] + tonal.pspeech[1]; float num51 = tonal.pmusic[0] + tonal.pmusic[1]; tonal.pspeech[0] = num50 * (1f - num41) * num48; tonal.pmusic[0] = num51 * (1f - num41) * num49; for (int i = 1; i < 199; i++) { tonal.pspeech[i] = tonal.pspeech[i + 1] * num48; tonal.pmusic[i] = tonal.pmusic[i + 1] * num49; } tonal.pspeech[199] = num51 * num41 * num48; tonal.pmusic[199] = num50 * num41 * num49; for (int i = 0; i < 200; i++) { num47 += tonal.pspeech[i] + tonal.pmusic[i]; } num47 = 1f / num47; for (int i = 0; i < 200; i++) { tonal.pspeech[i] *= num47; tonal.pmusic[i] *= num47; } num47 = tonal.pmusic[0]; for (int i = 1; i < 200; i++) { num47 += tonal.pspeech[i]; } if ((double)array5[1] > 0.75) { if ((double)tonal.music_prob > 0.9) { float num52 = 1f / (float)(++tonal.music_confidence_count); tonal.music_confidence_count = Inlines.IMIN(tonal.music_confidence_count, 500); tonal.music_confidence += num52 * Inlines.MAX16(-0.2f, array5[0] - tonal.music_confidence); } if ((double)tonal.music_prob < 0.1) { float num53 = 1f / (float)(++tonal.speech_confidence_count); tonal.speech_confidence_count = Inlines.IMIN(tonal.speech_confidence_count, 500); tonal.speech_confidence += num53 * Inlines.MIN16(0.2f, array5[0] - tonal.speech_confidence); } } else { if (tonal.music_confidence_count == 0) { tonal.music_confidence = 0.9f; } if (tonal.speech_confidence_count == 0) { tonal.speech_confidence = 0.1f; } } if (tonal.last_music != ((tonal.music_prob > 0.5f) ? 1 : 0)) { tonal.last_transition = 0; } tonal.last_music = ((tonal.music_prob > 0.5f) ? 1 : 0); analysisInfo.bandwidth = num5; analysisInfo.noisiness = num23; analysisInfo.valid = 1; } internal static void run_analysis<T>(TonalityAnalysisState analysis, CeltMode celt_mode, ReadOnlySpan<T> analysis_pcm, int analysis_frame_size, int frame_size, int c1, int c2, int C, int Fs, int lsb_depth, Downmix.downmix_func<T> downmix, AnalysisInfo analysis_info) { if (!analysis_pcm.IsEmpty) { analysis_frame_size = Inlines.IMIN(195 * Fs / 100, analysis_frame_size); int num = analysis_frame_size - analysis.analysis_offset; int num2 = analysis.analysis_offset; do { tonality_analysis(analysis, celt_mode, analysis_pcm, Inlines.IMIN(480, num), num2, c1, c2, C, lsb_depth, downmix); num2 += 480; num -= 480; } while (num > 0); analysis.analysis_offset = analysis_frame_size; analysis.analysis_offset -= frame_size; } analysis_info.valid = 0; tonality_get_info(analysis, analysis_info, frame_size); } } internal static class CodecHelpers { private const int MAX_DYNAMIC_FRAMESIZE = 24; internal static byte gen_toc(OpusMode mode, int framerate, OpusBandwidth bandwidth, int channels) { int num = 0; while (framerate < 400) { framerate <<= 1; num++; } byte b; switch (mode) { case OpusMode.MODE_SILK_ONLY: b = (byte)((int)(bandwidth - 1101) << 5); b |= (byte)(num - 2 << 3); break; case OpusMode.MODE_CELT_ONLY: { int num2 = (int)(bandwidth - 1102); if (num2 < 0) { num2 = 0; } b = 128; b |= (byte)(num2 << 5); b |= (byte)(num << 3); break; } default: b = 96; b |= (byte)((int)(bandwidth - 1104) << 4); b |= (byte)(num - 2 << 3); break; } return (byte)(b | (byte)(((channels == 2) ? 1u : 0u) << 2)); } internal static void hp_cutoff(ReadOnlySpan<short> input, int input_ptr, int cutoff_Hz, Span<short> output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) { int[] array = new int[3]; int[] array2 = new int[2]; int num = Inlines.silk_DIV32_16(Inlines.silk_SMULBB(2471, cutoff_Hz), Fs / 1000); int num2 = (array[0] = 268435456 - Inlines.silk_MUL(471, num)); array[1] = Inlines.silk_LSHIFT(-num2, 1); array[2] = num2; int num3 = Inlines.silk_RSHIFT(num2, 6); array2[0] = Inlines.silk_SMULWW(num3, Inlines.silk_SMULWW(num, num) - 8388608); array2[1] = Inlines.silk_SMULWW(num3, num3); Filters.silk_biquad_alt(input, input_ptr, array, array2, hp_mem, 0, output, output_ptr, len, channels); if (channels == 2) { Filters.silk_biquad_alt(input, input_ptr + 1, array, array2, hp_mem, 2, output, output_ptr + 1, len, channels); } } internal static void dc_reject(ReadOnlySpan<short> input, int input_ptr, int cutoff_Hz, Span<short> output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) { int shift = Inlines.celt_ilog2(Fs / (cutoff_Hz * 3)); for (int i = 0; i < channels; i++) { for (int j = 0; j < len; j++) { int num = Inlines.SHL32(Inlines.EXTEND32(input[channels * j + i + input_ptr]), 15); int num2 = num - hp_mem[2 * i]; hp_mem[2 * i] += Inlines.PSHR32(num - hp_mem[2 * i], shift); int a = num2 - hp_mem[2 * i + 1]; hp_mem[2 * i + 1] += Inlines.PSHR32(num2 - hp_mem[2 * i + 1], shift); output[channels * j + i + output_ptr] = Inlines.EXTRACT16(Inlines.SATURATE(Inlines.PSHR32(a, 15), 32767)); } } } internal static void stereo_fade(short[] pcm_buf, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs) { int num = 48000 / Fs; int num2 = overlap48 / num; g1 = 32767 - g1; g2 = 32767 - g2; int i; for (i = 0; i < num2; i++) { int num3 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]); int a = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num3, g2), 32767 - num3, g1), 15); int b = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1])); b = Inlines.MULT16_16_Q15(a, b); pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - b); pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + b); } for (; i < frame_size; i++) { int b2 = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1])); b2 = Inlines.MULT16_16_Q15(g2, b2); pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - b2); pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + b2); } } internal static void gain_fade(short[] buffer, int buf_ptr, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs) { int num = 48000 / Fs; int num2 = overlap48 / num; if (channels == 1) { for (int i = 0; i < num2; i++) { int num3 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]); int a = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num3, g2), 32767 - num3, g1), 15); buffer[buf_ptr + i] = (short)Inlines.MULT16_16_Q15(a, buffer[buf_ptr + i]); } } else { for (int i = 0; i < num2; i++) { int num4 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]); int a2 = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num4, g2), 32767 - num4, g1), 15); buffer[buf_ptr + i * 2] = (short)Inlines.MULT16_16_Q15(a2, buffer[buf_ptr + i * 2]); buffer[buf_ptr + i * 2 + 1] = (short)Inlines.MULT16_16_Q15(a2, buffer[buf_ptr + i * 2 + 1]); } } int num5 = 0; do { for (int i = num2; i < frame_size; i++) { buffer[buf_ptr + i * channels + num5] = (short)Inlines.MULT16_16_Q15(g2, buffer[buf_ptr + i * channels + num5]); } } while (++num5 < channels); } internal static float transient_boost(Span<float> E, int E_ptr, float[] E_1, int LM, int maxM) { float num = 0f; float num2 = 0f; int num3 = Inlines.IMIN(maxM, (1 << LM) + 1); for (int i = E_ptr; i < num3 + E_ptr; i++) { num += E[i]; num2 += E_1[i]; } float num4 = num * num2 / (float)(num3 * num3); return Inlines.MIN16(1f, (float)Math.Sqrt(Inlines.MAX16(0f, 0.05f * (num4 - 2f)))); } internal static int transient_viterbi(float[] E, float[] E_1, int N, int frame_cost, int rate) { float[][] array = Arrays.InitTwoDimensionalArray<float>(24, 16); int[][] array2 = Arrays.InitTwoDimensionalArray<int>(24, 16); float num = ((rate < 80) ? 0f : ((rate <= 160) ? (((float)rate - 80f) / 80f) : 1f)); for (int i = 0; i < 16; i++) { array2[0][i] = -1; array[0][i] = 1E+10f; } for (int i = 0; i < 4; i++) { array[0][1 << i] = (float)(frame_cost + rate * (1 << i)) * (1f + num * transient_boost(E, 0, E_1, i, N + 1)); array2[0][1 << i] = i; } for (int i = 1; i < N; i++) { for (int j = 2; j < 16; j++) { array[i][j] = array[i - 1][j - 1]; array2[i][j] = j - 1; } for (int j = 0; j < 4; j++) { array2[i][1 << j] = 1; float num2 = array[i - 1][1]; for (int k = 1; k < 4; k++) { float num3 = array[i - 1][(1 << k + 1) - 1]; if (num3 < num2) { array2[i][1 << j] = (1 << k + 1) - 1; num2 = num3; } } float num4 = (float)(frame_cost + rate * (1 << j)) * (1f + num * transient_boost(E, i, E_1, j, N - i + 1)); array[i][1 << j] = num2; if (N - i < 1 << j) { array[i][1 << j] += num4 * (float)(N - i) / (float)(1 << j); } else { array[i][1 << j] += num4; } } } int num5 = 1; float num6 = array[N - 1][1]; for (int i = 2; i < 16; i++) { if (array[N - 1][i] < num6) { num6 = array[N - 1][i]; num5 = i; } } for (int i = N - 1; i >= 0; i--) { num5 = array2[i][num5]; } return num5; } internal static int optimize_framesize<T>(ReadOnlySpan<T> x, int len, int C, int Fs, int bitrate, int tonality, float[] mem, int buffering, Downmix.downmix_func<T> downmix) { float[] array = new float[28]; float[] array2 = new float[27]; int num = 0; int num2 = Fs / 400; int[] array3 = new int[num2]; array[0] = mem[0]; array2[0] = 1f / (1f + mem[0]); int num3; int num4; if (buffering != 0) { num3 = 2 * num2 - buffering; len -= num3; array[1] = mem[1]; array2[1] = 1f / (1f + mem[1]); array[2] = mem[2]; array2[2] = 1f / (1f + mem[2]); num4 = 3; } else { num4 = 1; num3 = 0; } int num5 = Inlines.IMIN(len / num2, 24); int num6 = 0; int i; for (i = 0; i < num5; i++) { float num7 = 1f; downmix(x, array3, 0, num2, i * num2 + num3, 0, -2, C); if (i == 0) { num6 = array3[0]; } for (int j = 0; j < num2; j++) { int num8 = array3[j]; num7 += (float)(num8 - num6) * (float)(num8 - num6); num6 = num8; } array[i + num4] = num7; array2[i + num4] = 1f / num7; } array[i + num4] = array[i + num4 - 1]; if (buffering != 0) { num5 = Inlines.IMIN(24, num5 + 2); } num = transient_viterbi(array, array2, num5, (int)((1f + 0.5f * (float)tonality) * (float)(60 * C + 40)), bitrate / 400); mem[0] = array[1 << num]; if (buffering != 0) { mem[1] = array[(1 << num) + 1]; mem[2] = array[(1 << num) + 2]; } return num; } internal static int frame_size_select(int frame_size, OpusFramesize variable_duration, int Fs) { if (frame_size < Fs / 400) { return -1; } int num; switch (variable_duration) { case OpusFramesize.OPUS_FRAMESIZE_ARG: num = frame_size; break; case OpusFramesize.OPUS_FRAMESIZE_VARIABLE: num = Fs / 50; break; case OpusFramesize.OPUS_FRAMESIZE_2_5_MS: case OpusFramesize.OPUS_FRAMESIZE_5_MS: case OpusFramesize.OPUS_FRAMESIZE_10_MS: case OpusFramesize.OPUS_FRAMESIZE_20_MS: case OpusFramesize.OPUS_FRAMESIZE_40_MS: case OpusFramesize.OPUS_FRAMESIZE_60_MS: num = Inlines.IMIN(3 * Fs / 50, Fs / 400 << (int)(variable_duration - 5001)); break; default: return -1; } if (num > frame_size) { return -1; } if (400 * num != Fs && 200 * num != Fs && 100 * num != Fs && 50 * num != Fs && 25 * num != Fs && 50 * num != 3 * Fs) { return -1; } return num; } internal static int compute_frame_size<T>(ReadOnlySpan<T> analysis_pcm, int frame_size, OpusFramesize variable_duration, int C, int Fs, int bitrate_bps, int delay_compensation, Downmix.downmix_func<T> downmix, float[] subframe_mem, bool analysis_enabled) { if (analysis_enabled && variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs / 200) { int num = 3; num = optimize_framesize(analysis_pcm, frame_size, C, Fs, bitrate_bps, 0, subframe_mem, delay_compensation, downmix); while (Fs / 400 << num > frame_size) { num--; } frame_size = Fs / 400 << num; } else { frame_size = frame_size_select(frame_size, variable_duration, Fs); } if (frame_size < 0) { return -1; } return frame_size; } internal static int compute_stereo_width(ReadOnlySpan<short> pcm, int pcm_ptr, int frame_size, int Fs, StereoWidthState mem) { int num = Fs / frame_size; int a = 32767 - 819175 / Inlines.IMAX(50, num); int num3; int num2; int num4 = (num3 = (num2 = 0)); for (int i = 0; i < frame_size - 3; i += 4) { int num5 = 0; int num6 = 0; int num7 = 0; int num8 = pcm_ptr + 2 * i; int num9 = pcm[num8]; int num10 = pcm[num8 + 1]; num5 = Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 = Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 = Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num9 = pcm[num8 + 2]; num10 = pcm[num8 + 3]; num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num9 = pcm[num8 + 4]; num10 = pcm[num8 + 5]; num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num9 = pcm[num8 + 6]; num10 = pcm[num8 + 7]; num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num4 += Inlines.SHR32(num5, 10); num3 += Inlines.SHR32(num6, 10); num2 += Inlines.SHR32(num7, 10); } mem.XX += Inlines.MULT16_32_Q15(a, num4 - mem.XX); mem.XY += Inlines.MULT16_32_Q15(a, num3 - mem.XY); mem.YY += Inlines.MULT16_32_Q15(a, num2 - mem.YY); mem.XX = Inlines.MAX32(0, mem.XX); mem.XY = Inlines.MAX32(0, mem.XY); mem.YY = Inlines.MAX32(0, mem.YY); if (Inlines.MAX32(mem.XX, mem.YY) > 210) { int num11 = Inlines.celt_sqrt(mem.XX); int num12 = Inlines.celt_sqrt(mem.YY); int num13 = Inlines.celt_sqrt(num11); int num14 = Inlines.celt_sqrt(num12); mem.XY = Inlines.MIN32(mem.XY, num11 * num12); int num15 = Inlines.SHR32(Inlines.frac_div32(mem.XY, 1 + Inlines.MULT16_16(num11, num12)), 16); int b = 32767 * Inlines.ABS16(num13 - num14) / (1 + num13 + num14); int num16 = Inlines.MULT16_16_Q15(Inlines.celt_sqrt(1073741824 - Inlines.MULT16_16(num15, num15)), b); mem.smoothed_width += (num16 - mem.smoothed_width) / num; mem.max_follower = Inlines.MAX16(mem.max_follower - 655 / num, mem.smoothed_width); } else { int num16 = 0; int num15 = 32767; int b = 0; } return Inlines.EXTRACT16(Inlines.MIN32(32767, 20 * mem.max_follower)); } internal static void smooth_fade(Span<short> in1, int in1_ptr, Span<short> in2, int in2_ptr, Span<short> output, int output_ptr, int overlap, int channels, int[] window, int Fs) { int num = 48000 / Fs; for (int i = 0; i < channels; i++) { for (int j = 0; j < overlap; j++) { int num2 = Inlines.MULT16_16_Q15(window[j * num], window[j * num]); output[output_ptr + j * channels + i] = (short)Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num2, in2[in2_ptr + j * channels + i]), 32767 - num2, in1[in1_ptr + j * channels + i]), 15); } } } internal static string opus_strerror(int error) { string[] array = new string[8] { "success", "invalid argument", "buffer too small", "internal error", "corrupted stream", "request not implemented", "invalid state", "memory allocation failed" }; if (error > 0 || error < -7) { return "unknown error"; } return array[-error]; } internal static string GetVersionString() { return "Concentus 2.1.2"; } } internal static class Downmix { internal delegate void downmix_func<T>(ReadOnlySpan<T> _x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C); internal static void downmix_float(ReadOnlySpan<float> x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C) { for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] = Inlines.FLOAT2INT16(x[(i + offset) * C + c1]); } if (c2 > -1) { for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] += Inlines.FLOAT2INT16(x[(i + offset) * C + c2]); } } else if (c2 == -2) { for (int j = 1; j < C; j++) { int num = j; for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] += Inlines.FLOAT2INT16(x[(i + offset) * C + num]); } } } int num2 = 4096; num2 = ((C != -2) ? (num2 / 2) : (num2 / C)); for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] *= num2; } } internal static void downmix_int(ReadOnlySpan<short> x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C) { for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] = x[(i + offset) * C + c1]; } if (c2 > -1) { for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] += x[(i + offset) * C + c2]; } } else if (c2 == -2) { for (int j = 1; j < C; j++) { for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] += x[(i + offset) * C + j]; } } } int num = 4096; num = ((C != -2) ? (num / 2) : (num / C)); for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] *= num; } } } internal static class MultiLayerPerceptron { private const int MAX_NEURONS = 100; internal static float tansig_approx(float x) { float num = 1f; if (!(x < 8f)) { return 1f; } if (!(x > -8f)) { return -1f; } if (x < 0f) { x = 0f - x; num = -1f; } int num2 = (int)Math.Floor(0.5f + 25f * x); x -= 0.04f * (float)num2; float num3 = Tables.tansig_table[num2]; float num4 = 1f - num3 * num3; num3 += x * num4 * (1f - num3 * x); return num * num3; } internal static void mlp_process(MLP m, float[] input, float[] output) { float[] array = new float[100]; float[] weights = m.weights; int num = 0; for (int i = 0; i < m.topo[1]; i++) { float num2 = weights[num]; num++; for (int j = 0; j < m.topo[0]; j++) { num2 += input[j] * weights[num]; num++; } array[i] = tansig_approx(num2); } for (int i = 0; i < m.topo[2]; i++) { float num3 = weights[num]; num++; for (int k = 0; k < m.topo[1]; k++) { num3 += array[k] * weights[num]; num++; } output[i] = tansig_approx(num3); } } } internal static class OpusCompare { private const int NBANDS = 21; private const int NFREQS = 240; private const int TEST_WIN_SIZE = 480; private const int TEST_WIN_STEP = 120; private static readonly int[] BANDS = new int[22] { 0, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 156, 200 }; private static void band_energy(Pointer<float> _out, Pointer<float> _ps, Pointer<int> _bands, int _nbands, Pointer<float> _in, int _nchannels, int _nframes, int _window_sz, int _step, int _downsample) { Pointer<float> pointer = Concentus.Common.CPlusPlus.Pointer.Malloc<float>((3 + _nchannels) * _window_sz); Pointer<float> pointer2 = pointer.Point(_window_sz); Pointer<float> pointer3 = pointer2.Point(_window_sz); Pointer<float> pointer4 = pointer3.Point(_window_sz); int num = _window_sz / 2; for (int i = 0; i < _window_sz; i++) { pointer[i] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * 2.0 / (double)(_window_sz - 1) * (double)i)); } for (int i = 0; i < _window_sz; i++) { pointer2[i] = (float)Math.Cos(Math.PI * 2.0 / (double)_window_sz * (double)i); } for (int i = 0; i < _window_sz; i++) { pointer3[i] = (float)Math.Sin(Math.PI * 2.0 / (double)_window_sz * (double)i); } for (int j = 0; j < _nframes; j++) { for (int k = 0; k < _nchannels; k++) { for (int l = 0; l < _window_sz; l++) { pointer4[k * _window_sz + l] = pointer[l] * _in[(j * _step + l) * _nchannels + k]; } } int i; for (int m = (i = 0); m < _nbands; m++) { float[] array = new float[2]; for (; i < _bands[m + 1]; i++) { for (int k = 0; k < _nchannels; k++) { int num2 = 0; float num3; float num4 = (num3 = 0f); for (int l = 0; l < _window_sz; l++) { num4 += pointer2[num2] * pointer4[k * _window_sz + l]; num3 -= pointer3[num2] * pointer4[k * _window_sz + l]; num2 += i; if (num2 >= _window_sz) { num2 -= _window_sz; } } num4 *= (float)_downsample; num3 *= (float)_downsample; _ps[(j * num + i) * _nchannels + k] = num4 * num4 + num3 * num3 + 100000f; array[k] += _ps[(j * num + i) * _nchannels + k]; } } if (_out != null) { _out[(j * _nbands + m) * _nchannels] = array[0] / (float)(_bands[m + 1] - _bands[m]); if (_nchannels == 2) { _out[(j * _nbands + m) * _nchannels + 1] = array[1] / (float)(_bands[m + 1] - _bands[m]); } } } } } internal static float compare(float[] x, float[] y, int nchannels, int rate = 48000) { int num = x.Length; int num2 = y.Length; int num3 = 21; int num4 = 240; if (rate != 8000 && rate != 12000 && rate != 16000 && rate != 24000 && rate != 48000) { throw new ArgumentException("Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n"); } int num5; if (rate != 48000) { num5 = 48000 / rate; switch (rate) { case 8000: num3 = 13; break; case 12000: num3 = 15; break; case 16000: num3 = 17; break; case 24000: num3 = 19; break; } num4 = 240 / num5; } else { num5 = 1; } if (num != num2 * num5) { throw new ArgumentException("Sample counts do not match"); } if (num < 480) { throw new ArgumentException("Insufficient sample data"); } int num6 = (num - 480 + 120) / 120; Pointer<float> pointer = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * 21 * nchannels); Pointer<float> pointer2 = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * 240 * nchannels); Pointer<float> pointer3 = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * num4 * nchannels); band_energy(pointer, pointer2, BANDS.GetPointer(), 21, x.GetPointer(), nchannels, num6, 480, 120, 1); band_energy(null, pointer3, BANDS.GetPointer(), num3, y.GetPointer(), nchannels, num6, 480 / num5, 120 / num5, num5); for (int i = 0; i < num6; i++) { int j; for (j = 1; j < 21; j++) { for (int k = 0; k < nchannels; k++) { pointer[(i * 21 + j) * nchannels + k] += 0.1f * pointer[(i * 21 + j - 1) * nchannels + k]; } } j = 20; while (j-- > 0) { for (int k = 0; k < nchannels; k++) { pointer[(i * 21 + j) * nchannels + k] += 0.03f * pointer[(i * 21 + j + 1) * nchannels + k]; } } if (i > 0) { for (j = 0; j < 21; j++) { for (int k = 0; k < nchannels; k++) { pointer[(i * 21 + j) * nchannels + k] += 0.5f * pointer[((i - 1) * 21 + j) * nchannels + k]; } } } if (nchannels == 2) { for (j = 0; j < 21; j++) { float num7 = pointer[(i * 21 + j) * nchannels]; float num8 = pointer[(i * 21 + j) * nchannels + 1]; pointer[(i * 21 + j) * nchannels] += 0.01f * num8; pointer[(i * 21 + j) * nchannels + 1] += 0.01f * num7; } } for (j = 0; j < num3; j++) { for (int l = BANDS[j]; l < BANDS[j + 1]; l++) { for (int k = 0; k < nchannels; k++) { pointer2[(i * 240 + l) * nchannels + k] += 0.1f * pointer[(i * 21 + j) * nchannels + k]; pointer3[(i * num4 + l) * nchannels + k] += 0.1f * pointer[(i * 21 + j) * nchannels + k]; } } } } for (int j = 0; j < num3; j++) { for (int l = BANDS[j]; l < BANDS[j + 1]; l++) { for (int k = 0; k < nchannels; k++) { float num9 = pointer2[l * nchannels + k]; float num10 = pointer3[l * nchannels + k]; for (int i = 1; i < num6; i++) { float num11 = pointer2[(i * 240 + l) * nchannels + k]; float num12 = pointer3[(i * num4 + l) * nchannels + k]; pointer2[(i * 240 + l) * nchannels + k] += num9; pointer3[(i * num4 + l) * nchannels + k] += num10; num9 = num11; num10 = num12; } } } } int num13 = rate switch { 48000 => BANDS[21], 12000 => BANDS[num3], _ => BANDS[num3] - 3, }; double num14 = 0.0; for (int i = 0; i < num6; i++) { double num15 = 0.0; for (int j = 0; j < num3; j++) { double num16 = 0.0; for (int l = BANDS[j]; l < BANDS[j + 1] && l < num13; l++) { for (int k = 0; k < nchannels; k++) { float num17 = pointer3[(i * num4 + l) * nchannels + k] / pointer2[(i * 240 + l) * nchannels + k]; float num18 = num17 - (float)Math.Log(num17) - 1f; if (l >= 79 && l <= 81) { num18 *= 0.1f; } if (l == 80) { num18 *= 0.1f; } num16 += (double)num18; } } num16 /= (double)((BANDS[j + 1] - BANDS[j]) * nchannels); num15 += num16 * num16; } num15 /= 21.0; num15 *= num15; num14 += num15 * num15; } num14 = Math.Pow(num14 / (double)num6, 0.0625); float result = (float)(100.0 * (1.0 - 0.5 * Math.Log(1.0 + num14) / Math.Log(1.13))); _ = 0f; return result; } } internal static class OpusConstants { internal const int OPUS_AUTO = -1000; internal const int OPUS_BITRATE_MAX = -1; internal const int NB_FRAMES = 8; internal const int NB_TBANDS = 18; internal const int NB_TOT_BANDS = 21; internal const int NB_TONAL_SKIP_BANDS = 9; internal const int ANALYSIS_BUF_SIZE = 720; internal const int DETECT_SIZE = 200; internal const int MAX_ENCODER_BUFFER = 480; } public class OpusException : Exception { public int OpusErrorCode { get; private set; } internal OpusException() : base("Unknown error") { OpusErrorCode = -100; } internal OpusException(string message) : base(message) { OpusErrorCode = -100; } internal OpusException(int opusError) : base(CodecHelpers.opus_strerror(opusError)) { OpusErrorCode = opusError; } internal OpusException(string message, int opusError) : base(message) { OpusErrorCode = opusError; } } internal static class OpusMultistream { internal static int validate_layout(ChannelLayout layout) { int num = layout.nb_streams + layout.nb_coupled_streams; if (num > 255) { return 0; } for (int i = 0; i < layout.nb_channels; i++) { if (layout.mapping[i] >= num && layout.mapping[i] != byte.MaxValue) { return 0; } } return 1; } internal static int get_left_channel(ChannelLayout layout, int stream_id, int prev) { for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++) { if (layout.mapping[i] == stream_id * 2) { return i; } } return -1; } internal static int get_right_channel(ChannelLayout layout, int stream_id, int prev) { for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++) { if (layout.mapping[i] == stream_id * 2 + 1) { return i; } } return -1; } internal static int get_mono_channel(ChannelLayout layout, int stream_id, int prev) { for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++) { if (layout.mapping[i] == stream_id + layout.nb_coupled_streams) { return i; } } return -1; } } internal static class Tables { internal static readonly float[] dct_table = new float[128] { 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.351851f, 0.33833f, 0.311806f, 0.2733f, 0.224292f, 0.166664f, 0.102631f, 0.034654f, -0.034654f, -0.102631f, -0.166664f, -0.224292f, -0.2733f, -0.311806f, -0.33833f, -0.351851f, 0.34676f, 0.293969f, 0.196424f, 0.068975f, -0.068975f, -0.196424f, -0.293969f, -0.34676f, -0.34676f, -0.293969f, -0.196424f, -0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.34676f, 0.33833f, 0.224292f, 0.034654f, -0.166664f, -0.311806f, -0.351851f, -0.2733f, -0.102631f, 0.102631f, 0.2733f, 0.351851f, 0.311806f, 0.166664f, -0.034654f, -0.224292f, -0.33833f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f, 0.311806f, 0.034654f, -0.2733f, -0.33833f, -0.102631f, 0.224292f, 0.351851f, 0.166664f, -0.166664f, -0.351851f, -0.224292f, 0.102631f, 0.33833f, 0.2733f, -0.034654f, -0.311806f, 0.293969f, -0.068975f, -0.34676f, -0.196424f, 0.196424f, 0.34676f, 0.068975f, -0.293969f, -0.293969f, 0.068975f, 0.34676f, 0.196424f, -0.196424f, -0.34676f, -0.068975f, 0.293969f, 0.2733f, -0.166664f, -0.33833f, 0.034654f, 0.351851f, 0.102631f, -0.311806f, -0.224292f, 0.224292f, 0.311806f, -0.102631f, -0.351851f, -0.034654f, 0.33833f, 0.166664f, -0.2733f }; internal static readonly float[] analysis_window = new float[240] { 4.3E-05f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f, 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f, 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.02059f, 0.02249f, 0.024472f, 0.026535f, 0.028679f, 0.030904f, 0.03321f, 0.035595f, 0.03806f, 0.040604f, 0.043227f, 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f, 0.070297f, 0.07368f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f, 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.12408f, 0.128428f, 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.1606f, 0.165435f, 0.170327f, 0.175276f, 0.18028f, 0.18534f, 0.190453f, 0.195619f, 0.200838f, 0.206107f, 0.211427f, 0.216797f, 0.222215f, 0.22768f, 0.233193f, 0.238751f, 0.244353f, 0.25f, 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.29067f, 0.296632f, 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.33928f, 0.345492f, 0.351729f, 0.357992f, 0.36428f, 0.37059f, 0.376923f, 0.383277f, 0.389651f, 0.396044f, 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f, 0.454249f, 0.46077f, 0.467298f, 0.473832f, 0.48037f, 0.486912f, 0.493455f, 0.5f, 0.506545f, 0.513088f, 0.51963f, 0.526168f, 0.532702f, 0.53923f, 0.545751f, 0.552264f, 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f, 0.610349f, 0.616723f, 0.623077f, 0.62941f, 0.63572f, 0.642008f, 0.648271f, 0.654508f, 0.66072f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f, 0.70933f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.75f, 0.755647f, 0.761249f, 0.766807f, 0.77232f, 0.777785f, 0.783203f, 0.788573f, 0.793893f, 0.799162f, 0.804381f, 0.809547f, 0.81466f, 0.81972f, 0.824724f, 0.829673f, 0.834565f, 0.8394f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f, 0.87592f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f, 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.92632f, 0.929703f, 0.933013f, 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f, 0.959396f, 0.96194f, 0.964405f, 0.96679f, 0.969096f, 0.971321f, 0.973465f, 0.975528f, 0.97751f, 0.97941f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f, 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f, 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1f }; internal static readonly int[] tbands = new int[19] { 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120 }; internal static readonly int[] extra_bands = new int[22] { 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200 }; internal static readonly float[] weights = new float[422] { -0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f, -0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f, -0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f, 0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f, 0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f, 24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f, -0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f, -0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f, -0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f, 1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f, 15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f, 0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f, -0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f, 0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f, 0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f, -1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f, -0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f, -0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f, 0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f, -0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f, 2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f, 0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f, -0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f, 0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f, 0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f, -4.60683f, 1.4697f, 325f / (356f * MathF.E), -1.81905f, -30.1699f, 5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f, -0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f, -0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f, -0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f, 1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f, -7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f, -0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f, 0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f, 0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f, -0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f, 10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f, -0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f, -0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f, -0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f, 0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f, -0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f, 0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f, 0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f, -0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f, 0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f, -0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f, -0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f, -0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f, -0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f, -0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f, 5.8427f, -0.38075f, 0.221894f, -1.41934f, -1879430f, 1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f, 0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f, -0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f, 0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f, -0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f, -975268f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f, 0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f, -0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f, -2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f, 0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f, -6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f, 0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f, -0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f, -0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f, 0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f, -0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f, 0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f, -0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f, 0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f, -2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f, 4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f, 0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f, -0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f, 0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f, 0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f, 3.95279f, 1.89068f, 0.486087f, -11.3343f, 3941600f, -0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f, 0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f, 0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f, 0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f, 4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f, -1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f, 3.87308f, 3.52558f }; internal static readonly int[] topo = new int[3] { 25, 15, 2 }; internal static readonly MLP net = new MLP { layers = 3, topo = topo, weights = weights }; internal static readonly float[] tansig_table = new float[201] { 0f, 0.039979f, 0.07983f, 0.119427f, 0.158649f, 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f, 0.446244f, 0.4777f, 0.507977f, 0.53705f, 0.5649f, 0.591519f, 0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.82104f, 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.91542f, 0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.96109f, 0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.99202f, 0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.99759f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, 0.99955f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f, 0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.99997f, 0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.99998f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, 0.999988f, 0.999989f, 0.99999f, 0.99999f, 0.999991f, 0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f }; internal static readonly int[] mono_voice_bandwidth_thresholds = new int[8] { 11000, 1000, 14000, 1000, 17000, 1000, 21000, 2000 }; internal static readonly int[] mono_music_bandwidth_thresholds = new int[8] { 12000, 1000, 15000, 1000, 18000, 2000, 22000, 2000 }; internal static readonly int[] stereo_voice_bandwidth_thresholds = new int[8] { 11000, 1000, 14000, 1000, 21000, 2000, 28000, 2000 }; internal static readonly int[] stereo_music_bandwidth_thresholds = new int[8] { 12000, 1000, 18000, 2000, 21000, 2000, 30000, 2000 }; internal const int stereo_voice_threshold = 30000; internal const int stereo_music_threshold = 30000; internal static readonly int[][] mode_thresholds = new int[2][] { new int[2] { 64000, 16000 }, new int[2] { 36000, 16000 } }; } public static class ResamplerFactory { public static IResampler CreateResampler(int numChannels, int inRate, int outRate, int quality, TextWriter logger = null) { return CreateResampler(numChannels, inRate, outRate, inRate, outRate, quality, logger); } public static IResampler CreateResampler(int numChannels, int ratioNum, int ratioDen, int inRate, int outRate, int quality, TextWriter logger = null) { if (numChannels <= 0) { throw new ArgumentOutOfRangeException("numChannels"); } if (ratioNum <= 0) { throw new ArgumentOutOfRangeException("ratioNum"); } if (ratioDen <= 0) { throw new ArgumentOutOfRangeException("ratioDen"); } if (inRate <= 0) { throw new ArgumentOutOfRangeException("inRate"); } if (outRate <= 0) { throw new ArgumentOutOfRangeException("outRate"); } if (quality < 0 || quality > 10) { throw new ArgumentOutOfRangeException("quality", "Quality must be between 0 and 10"); } return new SpeexResampler(numChannels, ratioNum, ratioDen, inRate, outRate, quality); } } } namespace Concentus.Silk { internal static class ApplySineWindow { private static readonly short[] freq_table_Q16 = new short[27] { 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702 }; internal static void silk_apply_sine_window(short[] px_win, int px_win_ptr, short[] px, int px_ptr, int win_type, int length) { int num = (length >> 2) - 4; int num2 = freq_table_Q16[num]; int num3 = Inlines.silk_SMULWB(num2, -num2); int num4; int num5; if (win_type == 1) { num4 = 0; num5 = num2 + Inlines.silk_RSHIFT(length, 3); } else { num4 = 65536; num5 = 65536 + Inlines.silk_RSHIFT(num3, 1) + Inlines.silk_RSHIFT(length, 4); } for (num = 0; num < length; num += 4) { int num6 = px_win_ptr + num; int num7 = px_ptr + num; px_win[num6] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(num4 + num5, 1), px[num7]); px_win[num6 + 1] = (short)Inlines.silk_SMULWB(num5, px[num7 + 1]); num4 = Inlines.silk_SMULWB(num5, num3) + Inlines.silk_LSHIFT(num5, 1) - num4 + 1; num4 = Inlines.silk_min(num4, 65536); px_win[num6 + 2] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(num4 + num5, 1), px[num7 + 2]); px_win[num6 + 3] = (short)Inlines.silk_SMULWB(num4, px[num7 + 3]); num5 = Inlines.silk_SMULWB(num4, num3) + Inlines.silk_LSHIFT(num4, 1) - num5; num5 = Inlines.silk_min(num5, 65536); } } } internal static class BurgModified { private const int MAX_FRAME_SIZE = 384; private const int QA = 25; private const int N_BITS_HEAD_ROOM = 2; private const int MIN_RSHIFTS = -16; private const int MAX_RSHIFTS = 7; internal static void silk_burg_modified(BoxedValueInt res_nrg, BoxedValueInt res_nrg_Q, int[] A_Q16, short[] x, int x_ptr, int minInvGain_Q30, int subfr_length, int nb_subfr, int D) { int[] array = new int[16]; int[] array2 = new int[16]; int[] array3 = new int[16]; int[] array4 = new int[17]; int[] array5 = new int[17]; int[] array6 = new int[16]; long num = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr); int num2 = Inlines.silk_CLZ64(num); int num3 = 35 - num2; if (num3 > 7) { num3 = 7; } if (num3 < -16) { num3 = -16; } int num4 = (int)((num3 <= 0) ? Inlines.silk_LSHIFT32((int)num, -num3) : Inlines.silk_RSHIFT64(num, num3)); array5[0] = (array4[0] = num4 + Inlines.silk_SMMUL(42950, num4) + 1); Arrays.MemSetInt(array, 0, 16); if (num3 > 0) { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; for (int j = 1; j < D + 1; j++) { array[j - 1] += (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, num5, x, num5 + j, subfr_length - j), num3); } } } else { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; CeltPitchXCorr.pitch_xcorr(x, num5, x, num5 + 1, array6, subfr_length - D, D); for (int j = 1; j < D + 1; j++) { int k = j + subfr_length - D; int num6 = 0; for (; k < subfr_length; k++) { num6 = Inlines.MAC16_16(num6, x[num5 + k], x[num5 + k - j]); } array6[j - 1] += num6; } for (int j = 1; j < D + 1; j++) { array[j - 1] += Inlines.silk_LSHIFT32(array6[j - 1], -num3); } } } Arrays.MemCopy(array, 0, array2, 0, 16); array5[0] = (array4[0] = num4 + Inlines.silk_SMMUL(42950, num4) + 1); int num7 = 1073741824; int num8 = 0; for (int j = 0; j < D; j++) { int num9; int num10; if (num3 > -2) { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; int b = -Inlines.silk_LSHIFT32(x[num5 + j], 16 - num3); int b2 = -Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 16 - num3); num9 = Inlines.silk_LSHIFT32(x[num5 + j], 9); num10 = Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 9); for (int l = 0; l < j; l++) { array[l] = Inlines.silk_SMLAWB(array[l], b, x[num5 + j - l - 1]); array2[l] = Inlines.silk_SMLAWB(array2[l], b2, x[num5 + subfr_length - j + l]); int b3 = array3[l]; num9 = Inlines.silk_SMLAWB(num9, b3, x[num5 + j - l - 1]); num10 = Inlines.silk_SMLAWB(num10, b3, x[num5 + subfr_length - j + l]); } num9 = Inlines.silk_LSHIFT32(-num9, 7 - num3); num10 = Inlines.silk_LSHIFT32(-num10, 7 - num3); for (int l = 0; l <= j; l++) { array4[l] = Inlines.silk_SMLAWB(array4[l], num9, x[num5 + j - l]); array5[l] = Inlines.silk_SMLAWB(array5[l], num10, x[num5 + subfr_length - j + l - 1]); } } } else { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; int b = -Inlines.silk_LSHIFT32(x[num5 + j], -num3); int b2 = -Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], -num3); num9 = Inlines.silk_LSHIFT32(x[num5 + j], 17); num10 = Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 17); for (int l = 0; l < j; l++) { array[l] = Inlines.silk_MLA(array[l], b, x[num5 + j - l - 1]); array2[l] = Inlines.silk_MLA(array2[l], b2, x[num5 + subfr_length - j + l]); int c = Inlines.silk_RSHIFT_ROUND(array3[l], 8); num9 = Inlines.silk_MLA(num9, x[num5 + j - l - 1], c); num10 = Inlines.silk_MLA(num10, x[num5 + subfr_length - j + l], c); } num9 = -num9; num10 = -num10; for (int l = 0; l <= j; l++) { array4[l] = Inlines.silk_SMLAWW(array4[l], num9, Inlines.silk_LSHIFT32(x[num5 + j - l], -num3 - 1)); array5[l] = Inlines.silk_SMLAWW(array5[l], num10, Inlines.silk_LSHIFT32(x[num5 + subfr_length - j + l - 1], -num3 - 1)); } } } num9 = array[j]; num10 = array2[j]; int a = 0; int num11 = Inlines.silk_ADD32(array5[0], array4[0]); for (int l = 0; l < j; l++) { int b3 = array3[l]; num2 = Inlines.silk_CLZ32(Inlines.silk_abs(b3)) - 1; num2 = Inlines.silk_min(7, num2); int c = Inlines.silk_LSHIFT32(b3, num2); num9 = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(array2[j - l - 1], c), 7 - num2); num10 = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(array[j - l - 1], c), 7 - num2); a = Inlines.silk_ADD_LSHIFT32(a, Inlines.silk_SMMUL(array5[j - l], c), 7 - num2); num11 = Inlines.silk_ADD_LSHIFT32(num11, Inlines.silk_SMMUL(Inlines.silk_ADD32(array5[l + 1], array4[l + 1]), c), 7 - num2); } array4[j + 1] = num9; array5[j + 1] = num10; a = Inlines.silk_ADD32(a, num10); a = Inlines.silk_LSHIFT32(-a, 1); int num12 = ((Inlines.silk_abs(a) >= num11) ? ((a > 0) ? int.MaxValue : int.MinValue) : Inlines.silk_DIV32_varQ(a, num11, 31)); num9 = 1073741824 - Inlines.silk_SMMUL(num12, num12); num9 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(num7, num9), 2); if (num9 <= minInvGain_Q30) { num10 = 1073741824 - Inlines.silk_DIV32_varQ(minInvGain_Q30, num7, 30); num12 = Inlines.silk_SQRT_APPROX(num10); num12 = Inlines.silk_RSHIFT32(num12 + Inlines.silk_DIV32(num10, num12), 1); num12 = Inlines.silk_LSHIFT32(num12, 16); if (a < 0) { num12 = -num12; } num7 = minInvGain_Q30; num8 = 1; } else { num7 = num9; } for (int l = 0; l < j + 1 >> 1; l++) { num9 = array3[l]; num10 = array3[j - l - 1]; array3[l] = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(num10, num12), 1); array3[j - l - 1] = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(num9, num12), 1); } array3[j] = Inlines.silk_RSHIFT32(num12, 6); if (num8 != 0) { for (int l = j + 1; l < D; l++) { array3[l] = 0; } break; } for (int l = 0; l <= j + 1; l++) { num9 = array4[l]; num10 = array5[j - l + 1]; array4[l] = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(num10, num12), 1); array5[j - l + 1] = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(num9, num12), 1); } } if (num8 != 0) { for (int l = 0; l < D; l++) { A_Q16[l] = -Inlines.silk_RSHIFT_ROUND(array3[l], 9); } if (num3 > 0) { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; num4 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, num5, x, num5, D), num3); } } else { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; num4 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, num5, D), -num3); } } res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(num7, num4), 2); res_nrg_Q.Val = -num3; } else { int num11 = array4[0]; int num9 = 65536; for (int l = 0; l < D; l++) { int c = Inlines.silk_RSHIFT_ROUND(array3[l], 9); num11 = Inlines.silk_SMLAWW(num11, array4[l + 1], c); num9 = Inlines.silk_SMLAWW(num9, c, c); A_Q16[l] = -c; } res_nrg.Val = Inlines.silk_SMLAWW(num11, Inlines.silk_SMMUL(42950, num4), -num9); res_nrg_Q.Val = -num3; } } } internal static class BWExpander { internal static void silk_bwexpander_32(int[] ar, int d, int chirp_Q16) { int b = chirp_Q16 - 65536; for (int i = 0; i < d - 1; i++) { ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]); chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, b), 16); } ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]); } internal static void silk_bwexpander(short[] ar, int d, int chirp_Q16) { int b = chirp_Q16 - 65536; for (int i = 0; i < d - 1; i++) { ar[i] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[i]), 16); chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, b), 16); } ar[d - 1] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[d - 1]), 16); } } internal static class CNG { internal static void silk_CNG_exc(Span<int> exc_Q10, int exc_Q10_ptr, int[] exc_buf_Q14, int Gain_Q16, int length, ref int rand_seed) { int num; for (num = 255; num > length; num = Inlines.silk_RSHIFT(num, 1)) { } int num2 = rand_seed; for (int i = exc_Q10_ptr; i < exc_Q10_ptr + length; i++) { num2 = Inlines.silk_RAND(num2); int num3 = Inlines.silk_RSHIFT(num2, 24) & num; exc_Q10[i] = (short)Inlines.silk_SAT16(Inlines.silk_SMULWW(exc_buf_Q14[num3], Gain_Q16 >> 4)); } rand_seed = num2; } internal static void silk_CNG_Reset(SilkChannelDecoder psDec) { int num = Inlines.silk_DIV32_16(32767, (short)(psDec.LPC_order + 1)); int num2 = 0; for (int i = 0; i < psDec.LPC_order; i++) { num2 += num; psDec.sCNG.CNG_smth_NLSF_Q15[i] = (short)num2; } psDec.sCNG.CNG_smth_Gain_Q16 = 0; psDec.sCNG.rand_seed = 3176576; } internal static void silk_CNG(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span<short> frame, int frame_ptr, int length) { short[] array = new short[psDec.LPC_order]; CNGState sCNG = psDec.sCNG; if (psDec.fs_kHz != sCNG.fs_kHz) { silk_CNG_Reset(psDec); sCNG.fs_kHz = psDec.fs_kHz; } if (psDec.lossCnt == 0 && psDec.prevSignalType == 0) { for (int i = 0; i < psDec.LPC_order; i++) { sCNG.CNG_smth_NLSF_Q15[i] += (short)Inlines.silk_SMULWB(psDec.prevNLSF_Q15[i] - sCNG.CNG_smth_NLSF_Q15[i], 16348); } int num = 0; for (int i = 0; i < psDec.nb_subfr; i++) { if (psDecCtrl.Gains_Q16[i] > num) { num = psDecCtrl.Gains_Q16[i]; } } Arrays.MemMoveInt(sCNG.CNG_exc_buf_Q14, 0, psDec.subfr_length, (psDec.nb_subfr - 1) * psDec.subfr_length); for (int i = 0; i < psDec.nb_subfr; i++) { sCNG.CNG_smth_Gain_Q16 += Inlines.silk_SMULWB(psDecCtrl.Gains_Q16[i] - sCNG.CNG_smth_Gain_Q16, 4634); } } if (psDec.lossCnt != 0) { int[] array2 = new int[length + 16]; int num2 = Inlines.silk_SMULWW(psDec.sPLC.randScale_Q14, psDec.sPLC.prevGain_Q16[1]); if (num2 >= 2097152 || sCNG.CNG_smth_Gain_Q16 > 8388608) { num2 = Inlines.silk_SMULTT(num2, num2); num2 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULTT(sCNG.CNG_smth_Gain_Q16, sCNG.CNG_smth_Gain_Q16), num2, 5); num2 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(num2), 16); } else { num2 = Inlines.silk_SMULWW(num2, num2); num2 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULWW(sCNG.CNG_smth_Gain_Q16, sCNG.CNG_smth_Gain_Q16), num2, 5); num2 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(num2), 8); } silk_CNG_exc(array2, 16, sCNG.CNG_exc_buf_Q14, num2, length, ref sCNG.rand_seed); NLSF.silk_NLSF2A(array, sCNG.CNG_smth_NLSF_Q15, psDec.LPC_order); Arrays.MemCopy(sCNG.CNG_synth_state, 0, array2, 0, 16); for (int i = 0; i < length; i++) { int num3 = 16 + i; int a = Inlines.silk_RSHIFT(psDec.LPC_order, 1); a = Inlines.silk_SMLAWB(a, array2[num3 - 1], array[0]); a = Inlines.silk_SMLAWB(a, array2[num3 - 2], array[1]); a = Inlines.silk_SMLAWB(a, array2[num3 - 3], array[2]); a = Inlines.silk_SMLAWB(a, array2[num3 - 4], array[3]); a = Inlines.silk_SMLAWB(a, array2[num3 - 5], array[4]); a = Inlines.silk_SMLAWB(a, array2[num3 - 6], array[5]); a = Inlines.silk_SMLAWB(a, array2[num3 - 7], array[6]); a = Inlines.silk_SMLAWB(a, array2[num3 - 8], array[7]); a = Inlines.silk_SMLAWB(a, array2[num3 - 9], array[8]); a = Inlines.silk_SMLAWB(a, array2[num3 - 10], array[9]); if (psDec.LPC_order == 16) { a = Inlines.silk_SMLAWB(a, array2[num3 - 11], array[10]); a = Inlines.silk_SMLAWB(a, array2[num3 - 12], array[11]); a = Inlines.silk_SMLAWB(a, array2[num3 - 13], array[12]); a = Inlines.silk_SMLAWB(a, array2[num3 - 14], array[13]); a = Inlines.silk_SMLAWB(a, array2[num3 - 15], array[14]); a = Inlines.silk_SMLAWB(a, array2[num3 - 16], array[15]); } array2[num3] = Inlines.silk_ADD_LSHIFT(array2[num3], a, 4); frame[frame_ptr + i] = Inlines.silk_ADD_SAT16(frame[frame_ptr + i], (short)Inlines.silk_RSHIFT_ROUND(array2[num3], 10)); } Arrays.MemCopy(array2, length, sCNG.CNG_synth_state, 0, 16); } else { Arrays.MemSetInt(sCNG.CNG_synth_state, 0, psDec.LPC_order); } } } internal static class CodeSigns { private static int silk_enc_map(int a) { return Inlines.silk_RSHIFT(a, 15) + 1; } private static int silk_dec_map(int a) { return Inlines.silk_LSHIFT(a, 1) - 1; } internal static void silk_encode_signs(EntropyCoder psRangeEnc, Span<byte> encodedData, Span<sbyte> pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { byte[] array = new byte[2]; byte[] silk_sign_iCDF = Tables.silk_sign_iCDF; array[1] = 0; int num = 0; int num2 = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); int num3 = num2; length = Inlines.silk_RSHIFT(length + 8, 4); for (num2 = 0; num2 < length; num2++) { int num4 = sum_pulses[num2]; if (num4 > 0) { array[0] = silk_sign_iCDF[num3 + Inlines.silk_min(num4 & 0x1F, 6)]; for (int i = num; i < num + 16; i++) { if (pulses[i] != 0) { psRangeEnc.enc_icdf(encodedData, silk_enc_map(pulses[i]), array, 8u); } } } num += 16; } } internal static void silk_decode_signs(EntropyCoder psRangeDec, ReadOnlySpan<byte> encodedData, short[] pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { byte[] array = new byte[2]; byte[] silk_sign_iCDF = Tables.silk_sign_iCDF; array[1] = 0; int num = 0; int num2 = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); int num3 = num2; length = Inlines.silk_RSHIFT(length + 8, 4); for (num2 = 0; num2 < length; num2++) { int num4 = sum_pulses[num2]; if (num4 > 0) { array[0] = silk_sign_iCDF[num3 + Inlines.silk_min(num4 & 0x1F, 6)]; for (int i = 0; i < 16; i++) { if (pulses[num + i] > 0) { pulses[num + i] *= (short)silk_dec_map(psRangeDec.dec_icdf(encodedData, array, 8u)); } } } num += 16; } } } internal static class CorrelateMatrix { internal static void silk_corrVector(short[] x, int x_ptr, short[] t, int t_ptr, int L, int order, int[] Xt, int rshifts) { int num = x_ptr + order - 1; if (rshifts > 0) { for (int i = 0; i < order; i++) { int num2 = 0; for (int j = 0; j < L; j++) { num2 += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num + j], t[t_ptr + j]), rshifts); } Xt[i] = num2; num--; } } else { for (int i = 0; i < order; i++) { Xt[i] = Inlines.silk_inner_prod(x, num, t, t_ptr, L); num--; } } } internal static void silk_corrMatrix(short[] x, int x_ptr, int L, int order, int head_room, int[] XX, int XX_ptr, BoxedValueInt rshifts) { SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, x, x_ptr, L + order - 1); int num = Inlines.silk_max(head_room - Inlines.silk_CLZ32(energy), 0); energy = Inlines.silk_RSHIFT32(energy, num); shift += num; for (int i = x_ptr; i < x_ptr + order - 1; i++) { energy -= Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[i], x[i]), shift); } if (shift < rshifts.Val) { energy = Inlines.silk_RSHIFT32(energy, rshifts.Val - shift); shift = rshifts.Val; } Inlines.MatrixSet(XX, XX_ptr, 0, 0, order, energy); int num2 = x_ptr + order - 1; for (int j = 1; j < order; j++) { energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + L - j], x[num2 + L - j]), shift)); energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 - j], x[num2 - j]), shift)); Inlines.MatrixSet(XX, XX_ptr, j, j, order, energy); } int num3 = x_ptr + order - 2; if (shift > 0) { for (int k = 1; k < order; k++) { energy = 0; for (int i = 0; i < L; i++) { energy += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + i], x[num3 + i]), shift); } Inlines.MatrixSet(XX, XX_ptr, k, 0, order, energy); Inlines.MatrixSet(XX, XX_ptr, 0, k, order, energy); for (int j = 1; j < order - k; j++) { energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + L - j], x[num3 + L - j]), shift)); energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 - j], x[num3 - j]), shift)); Inlines.MatrixSet(XX, XX_ptr, k + j, j, order, energy); Inlines.MatrixSet(XX, XX_ptr, j, k + j, order, energy); } num3--; } } else { for (int k = 1; k < order; k++) { energy = Inlines.silk_inner_prod(x, num2, x, num3, L); Inlines.MatrixSet(XX, XX_ptr, k, 0, order, energy); Inlines.MatrixSet(XX, XX_ptr, 0, k, order, energy); for (int j = 1; j < order - k; j++) { energy = Inlines.silk_SUB32(energy, Inlines.silk_SMULBB(x[num2 + L - j], x[num3 + L - j])); energy = Inlines.silk_SMLABB(energy, x[num2 - j], x[num3 - j]); Inlines.MatrixSet(XX, XX_ptr, k + j, j, order, energy); Inlines.MatrixSet(XX, XX_ptr, j, k + j, order, energy); } num3--; } } rshifts.Val = shift; } } internal static class DecodeAPI { internal static int silk_InitDecoder(SilkDecoder decState) { decState.Reset(); int result = SilkError.SILK_NO_ERROR; SilkChannelDecoder[] channel_state = decState.channel_state; for (int i = 0; i < 2; i++) { result = channel_state[i].silk_init_decoder(); } decState.sStereo.Reset(); decState.prev_decode_only_middle = 0; return result; } internal static int silk_Decode(SilkDecoder psDec, DecControlState decControl, ReadOnlySpan<byte> frameData, int lostFlag, int newPacketFlag, EntropyCoder psRangeDec, Span<short> samplesOut, int samplesOut_ptr, out int nSamplesOut) { int num = 0; int num2 = SilkError.SILK_NO_ERROR; BoxedValueInt boxedValueInt = new BoxedValueInt(); int[] array = new int[2]; int[] array2 = new int[2]; SilkChannelDecoder[] channel_state = psDec.channel_state; nSamplesOut = 0; if (newPacketFlag != 0) { for (int i = 0; i < decControl.nChannelsInternal; i++) { channel_state[i].nFramesDecoded = 0; } } if (decControl.nChannelsInternal > psDec.nChannelsInternal) { num2 += channel_state[1].silk_init_decoder(); } int num3 = ((decControl.nChannelsInternal == 1 && psDec.nChannelsInternal == 2 && decControl.internalSampleRate == 1000 * channel_state[0].fs_kHz) ? 1 : 0); if (channel_state[0].nFramesDecoded == 0) { for (int i = 0; i < decControl.nChannelsInternal; i++) { if (decControl.payloadSize_ms == 0) { channel_state[i].nFramesPerPacket = 1; channel_state[i].nb_subfr = 2; } else if (decControl.payloadSize_ms == 10) { channel_state[i].nFramesPerPacket = 1; channel_state[i].nb_subfr = 2; } else if (decControl.payloadSize_ms == 20) { channel_state[i].nFramesPerPacket = 1; channel_state[i].nb_subfr = 4; } else if (decControl.payloadSize_ms == 40) { channel_state[i].nFramesPerPacket = 2; channel_state[i].nb_subfr = 4; } else { if (decControl.payloadSize_ms != 60) { return SilkError.SILK_DEC_INVALID_FRAME_SIZE; } channel_state[i].nFramesPerPacket = 3; channel_state[i].nb_subfr = 4; } int num4 = (decControl.internalSampleRate >> 10) + 1; if (num4 != 8 && num4 != 12 && num4 != 16) { return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY; } num2 += channel_state[i].silk_decoder_set_fs(num4, decControl.API_sampleRate); } } if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2 && (psDec.nChannelsAPI == 1 || psDec.nChannelsInternal == 1)) { Arrays.MemSetShort(psDec.sStereo.pred_prev_Q13, 0, 2); Arrays.MemSetShort(psDec.sStereo.sSide, 0, 2); channel_state[1].resampler_state.Assign(channel_state[0].resampler_state); } psDec.nChannelsAPI = decControl.nChannelsAPI; psDec.nChannelsInternal = decControl.nChannelsInternal; if (decControl.API_sampleRate > 48000 || decControl.API_sampleRate < 8000) { return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY; } if (lostFlag != 1 && channel_state[0].nFramesDecoded == 0) { for (int i = 0; i < decControl.nChannelsInternal; i++) { for (int j = 0; j < channel_state[i].nFramesPerPacket; j++) { channel_state[i].VAD_flags[j] = psRangeDec.dec_bit_logp(frameData, 1u); } channel_state[i].LBRR_flag = psRangeDec.dec_bit_logp(frameData, 1u); } for (int i = 0; i < decControl.nChannelsInternal; i++) { Arrays.MemSetInt(channel_state[i].LBRR_flags, 0, 3); if (channel_state[i].LBRR_flag == 0) { continue; } if (channel_state[i].nFramesPerPacket == 1) { channel_state[i].LBRR_flags[0] = 1; continue; } int a = psRangeDec.dec_icdf(frameData, Tables.silk_LBRR_flags_iCDF_ptr[channel_state[i].nFramesPerPacket - 2], 8u) + 1; for (int j = 0; j < channel_state[i].nFramesPerPacket; j++) { channel_state[i].LBRR_flags[j] = Inlines.silk_RSHIFT(a, j) & 1; } } if (lostFlag == 0) { for (int j = 0; j < channel_state[0].nFramesPerPacket; j++) { for (int i = 0; i < decControl.nChannelsInternal; i++) { if (channel_state[i].LBRR_flags[j] == 0) { continue; } short[] pulses = new short[320]; if (decControl.nChannelsInternal == 2 && i == 0) { Stereo.silk_stereo_decode_pred(psRangeDec, frameData, array2); if (channel_state[1].LBRR_flags[j] == 0) { BoxedValueInt boxedValueInt2 = new BoxedValueInt(num); Stereo.silk_stereo_decode_mid_only(psRangeDec, frameData, boxedValueInt2); num = boxedValueInt2.Val; } } DecodeIndices.silk_decode_indices(condCoding: (j > 0 && channel_state[i].LBRR_flags[j - 1] != 0) ? 2 : 0, psDec: channel_state[i], psRangeDec: psRangeDec, frameData: frameData, FrameIndex: j, decode_LBRR: 1); DecodePulses.silk_decode_pulses(psRangeDec, frameData, pulses, channel_state[i].indices.signalType, channel_state[i].indices.quantOffsetType, channel_state[i].frame_length); } } } } if (decControl.nChannelsInternal == 2) { if (lostFlag == 0 || (lostFlag == 2 && channel_state[0].LBRR_flags[channel_state[0].nFramesDecoded] == 1)) { Stereo.silk_stereo_decode_pred(psRangeDec, frameData, array2); if ((lostFlag == 0 && channel_state[1].VAD_flags[channel_state[0].nFramesDecoded] == 0) || (lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[0].nFramesDecoded] == 0)) { BoxedValueInt boxedValueInt3 = new BoxedValueInt(num); Stereo.silk_stereo_decode_mid_only(psRangeDec, frameData, boxedValueInt3); num = boxedValueInt3.Val; } else { num = 0; } } else { for (int i = 0; i < 2; i++) { array2[i] = psDec.sStereo.pred_prev_Q13[i]; } } } if (decControl.nChannelsInternal == 2 && num == 0 && psDec.prev_decode_only_middle == 1) { Arrays.MemSetShort(psDec.channel_state[1].outBuf, 0, 480); Arrays.MemSetInt(psDec.channel_state[1].sLPC_Q14_buf, 0, 16); psDec.channel_state[1].lagPrev = 100; psDec.channel_state[1].LastGainIndex = 10; psDec.channel_state[1].prevSignalType = 0; psDec.channel_state[1].first_frame_after_reset = 1; } int num5 = ((decControl.internalSampleRate * decControl.nChannelsInternal < decControl.API_sampleRate * decControl.nChannelsAPI) ? 1 : 0); Span<short> span; if (num5 != 0) { span = samplesOut; array[0] = samplesOut_ptr; array[1] = samplesOut_ptr + channel_state[0].frame_length + 2; } else { span = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)]; array[0] = 0; array[1] = channel_state[0].frame_length + 2; } int num6 = ((lostFlag != 0) ? ((psDec.prev_decode_only_middle == 0 || (decControl.nChannelsInternal == 2 && lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[1].nFramesDecoded] == 1)) ? 1 : 0) : ((num == 0) ? 1 : 0)); for (int i = 0; i < decControl.nChannelsInternal; i++) { if (i == 0 || num6 != 0) { int num7 = channel_state[0].nFramesDecoded - i; int condCoding2 = ((num7 > 0) ? ((lostFlag == 2) ? ((channel_state[i].LBRR_flags[num7 - 1] != 0) ? 2 : 0) : ((i > 0 && psDec.prev_decode_only_middle != 0) ? 1 : 2)) : 0); num2 += channel_state[i].silk_decode_frame(psRangeDec, frameData, span, array[i] + 2, boxedValueInt, lostFlag, condCoding2); } else { Arrays.MemSetWithOffset<short>(span, 0, array[i] + 2, boxedValueInt.Val); } channel_state[i].nFramesDecoded++; } if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2) { Stereo.silk_stereo_MS_to_LR(psDec.sStereo, span, array[0], span, array[1], array2, channel_state[0].fs_kHz, boxedValueInt.Val); } else { psDec.sStereo.sMid.AsSpan(0, 2).CopyTo(span.Slice(array[0])); span.Slice(array[0] + boxedValueInt.Val, 2).CopyTo(psDec.sStereo.sMid); } nSamplesOut = Inlines.silk_DIV32(boxedValueInt.Val * decControl.API_sampleRate, Inlines.silk_SMULBB(channel_state[0].fs_kHz, 1000)); Span<short> output; int num8; if (decControl.nChannelsAPI == 2) { output = new short[nSamplesOut]; num8 = 0; } else { output = samplesOut; num8 = samplesOut_ptr; } if (num5 != 0) { short[] array3 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)]; samplesOut.Slice(samplesOut_ptr, decControl.nChannelsInternal * (channel_state[0].frame_length + 2)).CopyTo(array3); span = array3; array[0] = 0; array[1] = channel_state[0].frame_length + 2; } for (int i = 0; i < Inlines.silk_min(decControl.nChannelsAPI, decControl.nChannelsInternal); i++) { num2 += Resampler.silk_resampler(channel_state[i].resampler_state, output, num8, span, array[i] + 1, boxedValueInt.Val); if (decControl.nChannelsAPI == 2) { int num9 = samplesOut_ptr + i; for (int j = 0; j < nSamplesOut; j++) { samplesOut[num9 + 2 * j] = output[num8 + j]; } } } if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 1) { if (num3 != 0) { num2 += Resampler.silk_resampler(channel_state[1].resampler_state, output, num8, span, array[0] + 1, boxedValueInt.Val); for (int j = 0; j < nSamplesOut; j++) { samplesOut[samplesOut_ptr + 1 + 2 * j] = output[num8 + j]; } } else { for (int j = 0; j < nSamplesOut; j++) { samplesOut[samplesOut_ptr + 1 + 2 * j] = samplesOut[samplesOut_ptr + 2 * j]; } } } if (channel_state[0].prevSignalType == 2) { int[] array4 = new int[3] { 6, 4, 3 }; decControl.prevPitchLag = channel_state[0].lagPrev * array4[channel_state[0].fs_kHz - 8 >> 2]; } else { decControl.prevPitchLag = 0; } if (lostFlag == 1) { for (int j = 0; j < psDec.nChannelsInternal; j++) { psDec.channel_state[j].LastGainIndex = 10; } } else { psDec.prev_decode_only_middle = num; } return num2; } } internal static class DecodeCore { internal static void silk_decode_core(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span<short> xq, int xq_ptr, short[] pulses) { int num = 0; short[] lTPCoef_Q = psDecCtrl.LTPCoef_Q14; short[] array = new short[psDec.ltp_mem_length]; int[] array2 = new int[psDec.ltp_mem_length + psDec.frame_length]; int[] array3 = new int[psDec.subfr_length]; int[] array4 = new int[psDec.subfr_length + 16]; int num2 = Tables.silk_Quantization_Offsets_Q10[psDec.indices.signalType >> 1][psDec.indices.quantOffsetType]; int num3 = ((psDec.indices.NLSFInterpCoef_Q2 < 4) ? 1 : 0); int seed = psDec.indices.Seed; for (int i = 0; i < psDec.frame_length; i++) { seed = Inlines.silk_RAND(seed); psDec.exc_Q14[i] = Inlines.silk_LSHIFT(pulses[i], 14); if (psDec.exc_Q14[i] > 0) { psDec.exc_Q14[i] -= 1280; } else if (psDec.exc_Q14[i] < 0) { psDec.exc_Q14[i] += 1280; } psDec.exc_Q14[i] += num2 << 4; if (seed < 0) { psDec.exc_Q14[i] = -psDec.exc_Q14[i]; } seed = Inlines.silk_ADD32_ovflw(seed, pulses[i]); } Arrays.MemCopy(psDec.sLPC_Q14_buf, 0, array4, 0, 16); int num4 = 0; int num5 = xq_ptr; int num6 = psDec.ltp_mem_length; for (int j = 0; j < psDec.nb_subfr; j++) { int[] array5 = array3; int num7 = 0; short[] array6 = psDecCtrl.PredCoef_Q12[j >> 1]; int num8 = j * 5; int num9 = psDec.indices.signalType; int b = Inlines.silk_RSHIFT(psDecCtrl.Gains_Q16[j], 6); int a = Inlines.silk_INVERSE32_varQ(psDecCtrl.Gains_Q16[j], 47); int num10; if (psDecCtrl.Gains_Q16[j] != psDec.prev_gain_Q16) { num10 = Inlines.silk_DIV32_varQ(psDec.prev_gain_Q16, psDecCtrl.Gains_Q16[j], 16); for (int i = 0; i < 16; i++) { array4[i] = Inlines.silk_SMULWW(num10, array4[i]); } } else { num10 = 65536; } psDec.prev_gain_Q16 = psDecCtrl.Gains_Q16[j]; if (psDec.lossCnt != 0 && psDec.prevSignalType == 2 && psDec.indices.signalType != 2 && j < 2) { Arrays.MemSetWithOffset(lTPCoef_Q, (short)0, num8, 5); lTPCoef_Q[num8 + 2] = 4096; num9 = 2; psDecCtrl.pitchL[j] = psDec.lagPrev; } if (num9 == 2) { num = psDecCtrl.pitchL[j]; if (j == 0 || (j == 2 && num3 != 0)) { int num11 = psDec.ltp_mem_length - num - psDec.LPC_order - 2; if (j == 2) { xq.Slice(xq_ptr, 2 * psDec.subfr_length).CopyTo(psDec.outBuf.AsSpan(psDec.ltp_mem_length)); } Filters.silk_LPC_analysis_filter(array, num11, psDec.outBuf, num11 + j * psDec.subfr_length, array6, 0, psDec.ltp_mem_length - num11, psDec.LPC_order); if (j == 0) { a = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(a, psDecCtrl.LTP_scale_Q14), 2); } for (int i = 0; i < num + 2; i++) { array2[num6 - i - 1] = Inlines.silk_SMULWB(a, array[psDec.ltp_mem_length - i - 1]); } } else if (num10 != 65536) { for (int i = 0; i < num + 2; i++) { array2[num6 - i - 1] = Inlines.silk_SMULWW(num10, array2[num6 - i - 1]); } } } if (num9 == 2) { int num12 = num6 - num + 2; for (int i = 0; i < psDec.subfr_length; i++) { int a2 = 2; a2 = Inlines.silk_SMLAWB(a2, array2[num12], lTPCoef_Q[num8]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 1], lTPCoef_Q[num8 + 1]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 2], lTPCoef_Q[num8 + 2]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 3], lTPCoef_Q[num8 + 3]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 4], lTPCoef_Q[num8 + 4]); num12++; array5[num7 + i] = Inlines.silk_ADD_LSHIFT32(psDec.exc_Q14[num4 + i], a2, 1); array2[num6] = Inlines.silk_LSHIFT(array5[num7 + i], 1); num6++; } } else { array5 = psDec.exc_Q14; num7 = num4; } for (int i = 0; i < psDec.subfr_length; i++) { int a3 = Inlines.silk_RSHIFT(psDec.LPC_order, 1); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 1], array6[0]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 2], array6[1]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 3], array6[2]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 4], array6[3]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 5], array6[4]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 6], array6[5]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 7], array6[6]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 8], array6[7]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 9], array6[8]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 10], array6[9]); if (psDec.LPC_order == 16) { a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 11], array6[10]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 12], array6[11]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 13], array6[12]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 14], array6[13]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 15], array6[14]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 16], array6[15]); } array4[16 + i] = Inlines.silk_ADD_LSHIFT32(array5[num7 + i], a3, 4); xq[num5 + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(array4[16 + i], b), 8)); } Arrays.MemCopy(array4, psDec.subfr_length, array4, 0, 16); num4 += psDec.subfr_length; num5 += psDec.subfr_length; } Arrays.MemCopy(array4, 0, psDec.sLPC_Q14_buf, 0, 16); } } internal static class DecodeIndices { internal static void silk_decode_indices(SilkChannelDecoder psDec, EntropyCoder psRangeDec, ReadOnlySpan<byte> frameData, int FrameIndex, int decode_LBRR, int condCoding) { short[] array = new short[psDec.LPC_order]; byte[] array2 = new byte[psDec.LPC_order]; int num = ((decode_LBRR == 0 && psDec.VAD_flags[FrameIndex] == 0) ? psRangeDec.dec_icdf(frameData, Tables.silk_type_offset_no_VAD_iCDF, 8u) : (psRangeDec.dec_icdf(frameData, Tables.silk_type_offset_VAD_iCDF, 8u) + 2)); psDec.indices.signalType = (sbyte)Inlines.silk_RSHIFT(num, 1); psDec.indices.quantOffsetType = (sbyte)(num & 1); if (condCoding == 2) { psDec.indices.GainsIndices[0] = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_delta_gain_iCDF, 8u); } else { psDec.indices.GainsIndices[0] = (sbyte)Inlines.silk_LSHIFT(psRangeDec.dec_icdf(frameData, Tables.silk_gain_iCDF[psDec.indices.signalType], 8u), 3); psDec.indices.GainsIndices[0] += (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_uniform8_iCDF, 8u); } for (int i = 1; i < psDec.nb_subfr; i++) { psDec.indices.GainsIndices[i] = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_delta_gain_iCDF, 8u); } psDec.indices.NLSFIndices[0] = (sbyte)psRangeDec.dec_icdf(frameData, psDec.psNLSF_CB.CB1_iCDF, (psDec.indices.signalType >> 1) * psDec.psNLSF_CB.nVectors, 8u); NLSF.silk_NLSF_unpack(array, array2, psDec.psNLSF_CB, psDec.indices.NLSFIndices[0]); for (int i = 0; i < psDec.psNLSF_CB.order; i++) { num = psRangeDec.dec_icdf(frameData, psDec.psNLSF_CB.ec_iCDF, array[i], 8u); switch (num) { case 0: num -= psRangeDec.dec_icdf(frameData, Tables.silk_NLSF_EXT_iCDF, 8u); break; case 8: num += psRangeDec.dec_icdf(frameData, Tables.silk_NLSF_EXT_iCDF, 8u); break; } psDec.indices.NLSFIndices[i + 1] = (sbyte)(num - 4); } if (psDec.nb_subfr == 4) { psDec.indices.NLSFInterpCoef_Q2 = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_NLSF
Mods/LiteNetLib.dll
Decompiled 13 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using LiteNetLib.Layers; using LiteNetLib.Utils; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: AssemblyCompany("Ruslan Pyrch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright 2024 Ruslan Pyrch")] [assembly: AssemblyDescription("Lite reliable UDP library for .NET, Mono, and .NET Core")] [assembly: AssemblyFileVersion("1.3.1")] [assembly: AssemblyInformationalVersion("1.0.0+f57b9eafe72b924681a371d671af911478b6ab88")] [assembly: AssemblyProduct("LiteNetLib")] [assembly: AssemblyTitle("LiteNetLib")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/RevenantX/LiteNetLib")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.1.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } } namespace LiteNetLib { internal abstract class BaseChannel { protected readonly NetPeer Peer; protected readonly Queue<NetPacket> OutgoingQueue = new Queue<NetPacket>(64); private int _isAddedToPeerChannelSendQueue; public int PacketsInQueue => OutgoingQueue.Count; protected BaseChannel(NetPeer peer) { Peer = peer; } public void AddToQueue(NetPacket packet) { lock (OutgoingQueue) { OutgoingQueue.Enqueue(packet); } AddToPeerChannelSendQueue(); } protected void AddToPeerChannelSendQueue() { if (Interlocked.CompareExchange(ref _isAddedToPeerChannelSendQueue, 1, 0) == 0) { Peer.AddToReliableChannelSendQueue(this); } } public bool SendAndCheckQueue() { bool num = SendNextPackets(); if (!num) { Interlocked.Exchange(ref _isAddedToPeerChannelSendQueue, 0); } return num; } protected abstract bool SendNextPackets(); public abstract bool ProcessPacket(NetPacket packet); } internal enum ConnectionRequestResult { None, Accept, Reject, RejectForce } public class ConnectionRequest { private readonly NetManager _listener; private int _used; internal NetConnectRequestPacket InternalPacket; public readonly IPEndPoint RemoteEndPoint; public NetDataReader Data => InternalPacket.Data; internal ConnectionRequestResult Result { get; private set; } internal void UpdateRequest(NetConnectRequestPacket connectRequest) { if (connectRequest.ConnectionTime >= InternalPacket.ConnectionTime && (connectRequest.ConnectionTime != InternalPacket.ConnectionTime || connectRequest.ConnectionNumber != InternalPacket.ConnectionNumber)) { InternalPacket = connectRequest; } } private bool TryActivate() { return Interlocked.CompareExchange(ref _used, 1, 0) == 0; } internal ConnectionRequest(IPEndPoint remoteEndPoint, NetConnectRequestPacket requestPacket, NetManager listener) { InternalPacket = requestPacket; RemoteEndPoint = remoteEndPoint; _listener = listener; } public NetPeer AcceptIfKey(string key) { if (!TryActivate()) { return null; } try { if (Data.GetString() == key) { Result = ConnectionRequestResult.Accept; } } catch { NetDebug.WriteError("[AC] Invalid incoming data"); } if (Result == ConnectionRequestResult.Accept) { return _listener.OnConnectionSolved(this, null, 0, 0); } Result = ConnectionRequestResult.Reject; _listener.OnConnectionSolved(this, null, 0, 0); return null; } public NetPeer Accept() { if (!TryActivate()) { return null; } Result = ConnectionRequestResult.Accept; return _listener.OnConnectionSolved(this, null, 0, 0); } public void Reject(byte[] rejectData, int start, int length, bool force) { if (TryActivate()) { Result = (force ? ConnectionRequestResult.RejectForce : ConnectionRequestResult.Reject); _listener.OnConnectionSolved(this, rejectData, start, length); } } public void Reject(byte[] rejectData, int start, int length) { Reject(rejectData, start, length, force: false); } public void RejectForce(byte[] rejectData, int start, int length) { Reject(rejectData, start, length, force: true); } public void RejectForce() { Reject(null, 0, 0, force: true); } public void RejectForce(byte[] rejectData) { Reject(rejectData, 0, rejectData.Length, force: true); } public void RejectForce(NetDataWriter rejectData) { Reject(rejectData.Data, 0, rejectData.Length, force: true); } public void Reject() { Reject(null, 0, 0, force: false); } public void Reject(byte[] rejectData) { Reject(rejectData, 0, rejectData.Length, force: false); } public void Reject(NetDataWriter rejectData) { Reject(rejectData.Data, 0, rejectData.Length, force: false); } } public enum UnconnectedMessageType { BasicMessage, Broadcast } public enum DisconnectReason { ConnectionFailed, Timeout, HostUnreachable, NetworkUnreachable, RemoteConnectionClose, DisconnectPeerCalled, ConnectionRejected, InvalidProtocol, UnknownHost, Reconnect, PeerToPeerConnection, PeerNotFound } public struct DisconnectInfo { public DisconnectReason Reason; public SocketError SocketErrorCode; public NetPacketReader AdditionalData; } public interface INetEventListener { void OnPeerConnected(NetPeer peer); void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo); void OnNetworkError(IPEndPoint endPoint, SocketError socketError); void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod); void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType); void OnNetworkLatencyUpdate(NetPeer peer, int latency); void OnConnectionRequest(ConnectionRequest request); } public interface IDeliveryEventListener { void OnMessageDelivered(NetPeer peer, object userData); } public interface INtpEventListener { void OnNtpResponse(NtpPacket packet); } public interface IPeerAddressChangedListener { void OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress); } public class EventBasedNetListener : INetEventListener, IDeliveryEventListener, INtpEventListener, IPeerAddressChangedListener { public delegate void OnPeerConnected(NetPeer peer); public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo); public delegate void OnNetworkError(IPEndPoint endPoint, SocketError socketError); public delegate void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod); public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType); public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency); public delegate void OnConnectionRequest(ConnectionRequest request); public delegate void OnDeliveryEvent(NetPeer peer, object userData); public delegate void OnNtpResponseEvent(NtpPacket packet); public delegate void OnPeerAddressChangedEvent(NetPeer peer, IPEndPoint previousAddress); public event OnPeerConnected PeerConnectedEvent; public event OnPeerDisconnected PeerDisconnectedEvent; public event OnNetworkError NetworkErrorEvent; public event OnNetworkReceive NetworkReceiveEvent; public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent; public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent; public event OnConnectionRequest ConnectionRequestEvent; public event OnDeliveryEvent DeliveryEvent; public event OnNtpResponseEvent NtpResponseEvent; public event OnPeerAddressChangedEvent PeerAddressChangedEvent; public void ClearPeerConnectedEvent() { this.PeerConnectedEvent = null; } public void ClearPeerDisconnectedEvent() { this.PeerDisconnectedEvent = null; } public void ClearNetworkErrorEvent() { this.NetworkErrorEvent = null; } public void ClearNetworkReceiveEvent() { this.NetworkReceiveEvent = null; } public void ClearNetworkReceiveUnconnectedEvent() { this.NetworkReceiveUnconnectedEvent = null; } public void ClearNetworkLatencyUpdateEvent() { this.NetworkLatencyUpdateEvent = null; } public void ClearConnectionRequestEvent() { this.ConnectionRequestEvent = null; } public void ClearDeliveryEvent() { this.DeliveryEvent = null; } public void ClearNtpResponseEvent() { this.NtpResponseEvent = null; } public void ClearPeerAddressChangedEvent() { this.PeerAddressChangedEvent = null; } void INetEventListener.OnPeerConnected(NetPeer peer) { if (this.PeerConnectedEvent != null) { this.PeerConnectedEvent(peer); } } void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo) { if (this.PeerDisconnectedEvent != null) { this.PeerDisconnectedEvent(peer, disconnectInfo); } } void INetEventListener.OnNetworkError(IPEndPoint endPoint, SocketError socketErrorCode) { if (this.NetworkErrorEvent != null) { this.NetworkErrorEvent(endPoint, socketErrorCode); } } void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod) { if (this.NetworkReceiveEvent != null) { this.NetworkReceiveEvent(peer, reader, channelNumber, deliveryMethod); } } void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType) { if (this.NetworkReceiveUnconnectedEvent != null) { this.NetworkReceiveUnconnectedEvent(remoteEndPoint, reader, messageType); } } void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency) { if (this.NetworkLatencyUpdateEvent != null) { this.NetworkLatencyUpdateEvent(peer, latency); } } void INetEventListener.OnConnectionRequest(ConnectionRequest request) { if (this.ConnectionRequestEvent != null) { this.ConnectionRequestEvent(request); } } void IDeliveryEventListener.OnMessageDelivered(NetPeer peer, object userData) { if (this.DeliveryEvent != null) { this.DeliveryEvent(peer, userData); } } void INtpEventListener.OnNtpResponse(NtpPacket packet) { if (this.NtpResponseEvent != null) { this.NtpResponseEvent(packet); } } void IPeerAddressChangedListener.OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress) { if (this.PeerAddressChangedEvent != null) { this.PeerAddressChangedEvent(peer, previousAddress); } } } internal sealed class NetConnectRequestPacket { public const int HeaderSize = 18; public readonly long ConnectionTime; public byte ConnectionNumber; public readonly byte[] TargetAddress; public readonly NetDataReader Data; public readonly int PeerId; private NetConnectRequestPacket(long connectionTime, byte connectionNumber, int localId, byte[] targetAddress, NetDataReader data) { ConnectionTime = connectionTime; ConnectionNumber = connectionNumber; TargetAddress = targetAddress; Data = data; PeerId = localId; } public static int GetProtocolId(NetPacket packet) { return BitConverter.ToInt32(packet.RawData, 1); } public static NetConnectRequestPacket FromData(NetPacket packet) { if (packet.ConnectionNumber >= 4) { return null; } long connectionTime = BitConverter.ToInt64(packet.RawData, 5); int localId = BitConverter.ToInt32(packet.RawData, 13); int num = packet.RawData[17]; if (num != 16 && num != 28) { return null; } byte[] array = new byte[num]; Buffer.BlockCopy(packet.RawData, 18, array, 0, num); NetDataReader netDataReader = new NetDataReader(null, 0, 0); if (packet.Size > 18 + num) { netDataReader.SetSource(packet.RawData, 18 + num, packet.Size); } return new NetConnectRequestPacket(connectionTime, packet.ConnectionNumber, localId, array, netDataReader); } public static NetPacket Make(NetDataWriter connectData, SocketAddress addressBytes, long connectTime, int localId) { NetPacket netPacket = new NetPacket(PacketProperty.ConnectRequest, connectData.Length + addressBytes.Size); FastBitConverter.GetBytes(netPacket.RawData, 1, 13); FastBitConverter.GetBytes(netPacket.RawData, 5, connectTime); FastBitConverter.GetBytes(netPacket.RawData, 13, localId); netPacket.RawData[17] = (byte)addressBytes.Size; for (int i = 0; i < addressBytes.Size; i++) { netPacket.RawData[18 + i] = addressBytes[i]; } Buffer.BlockCopy(connectData.Data, 0, netPacket.RawData, 18 + addressBytes.Size, connectData.Length); return netPacket; } } internal sealed class NetConnectAcceptPacket { public const int Size = 15; public readonly long ConnectionTime; public readonly byte ConnectionNumber; public readonly int PeerId; public readonly bool PeerNetworkChanged; private NetConnectAcceptPacket(long connectionTime, byte connectionNumber, int peerId, bool peerNetworkChanged) { ConnectionTime = connectionTime; ConnectionNumber = connectionNumber; PeerId = peerId; PeerNetworkChanged = peerNetworkChanged; } public static NetConnectAcceptPacket FromData(NetPacket packet) { if (packet.Size != 15) { return null; } long connectionTime = BitConverter.ToInt64(packet.RawData, 1); byte b = packet.RawData[9]; if (b >= 4) { return null; } byte b2 = packet.RawData[10]; if (b2 > 1) { return null; } int num = BitConverter.ToInt32(packet.RawData, 11); if (num < 0) { return null; } return new NetConnectAcceptPacket(connectionTime, b, num, b2 == 1); } public static NetPacket Make(long connectTime, byte connectNum, int localPeerId) { NetPacket netPacket = new NetPacket(PacketProperty.ConnectAccept, 0); FastBitConverter.GetBytes(netPacket.RawData, 1, connectTime); netPacket.RawData[9] = connectNum; FastBitConverter.GetBytes(netPacket.RawData, 11, localPeerId); return netPacket; } public static NetPacket MakeNetworkChanged(NetPeer peer) { NetPacket netPacket = new NetPacket(PacketProperty.PeerNotFound, 14); FastBitConverter.GetBytes(netPacket.RawData, 1, peer.ConnectTime); netPacket.RawData[9] = peer.ConnectionNum; netPacket.RawData[10] = 1; FastBitConverter.GetBytes(netPacket.RawData, 11, peer.RemoteId); return netPacket; } } internal static class NativeSocket { private static class WinSock { private const string LibName = "ws2_32.dll"; [DllImport("ws2_32.dll", SetLastError = true)] public static extern int recvfrom(IntPtr socketHandle, [In][Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize); [DllImport("ws2_32.dll", SetLastError = true)] internal unsafe static extern int sendto(IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize); } private static class UnixSock { private const string LibName = "libc"; [DllImport("libc", SetLastError = true)] public static extern int recvfrom(IntPtr socketHandle, [In][Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize); [DllImport("libc", SetLastError = true)] internal unsafe static extern int sendto(IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize); } public static readonly bool IsSupported; public static readonly bool UnixMode; public const int IPv4AddrSize = 16; public const int IPv6AddrSize = 28; public const int AF_INET = 2; public const int AF_INET6 = 10; private static readonly Dictionary<int, SocketError> NativeErrorToSocketError; static NativeSocket() { IsSupported = false; UnixMode = false; NativeErrorToSocketError = new Dictionary<int, SocketError> { { 13, SocketError.AccessDenied }, { 98, SocketError.AddressAlreadyInUse }, { 99, SocketError.AddressNotAvailable }, { 97, SocketError.AddressFamilyNotSupported }, { 11, SocketError.WouldBlock }, { 114, SocketError.AlreadyInProgress }, { 9, SocketError.OperationAborted }, { 125, SocketError.OperationAborted }, { 103, SocketError.ConnectionAborted }, { 111, SocketError.ConnectionRefused }, { 104, SocketError.ConnectionReset }, { 89, SocketError.DestinationAddressRequired }, { 14, SocketError.Fault }, { 112, SocketError.HostDown }, { 6, SocketError.HostNotFound }, { 113, SocketError.HostUnreachable }, { 115, SocketError.InProgress }, { 4, SocketError.Interrupted }, { 22, SocketError.InvalidArgument }, { 106, SocketError.IsConnected }, { 24, SocketError.TooManyOpenSockets }, { 90, SocketError.MessageSize }, { 100, SocketError.NetworkDown }, { 102, SocketError.NetworkReset }, { 101, SocketError.NetworkUnreachable }, { 23, SocketError.TooManyOpenSockets }, { 105, SocketError.NoBufferSpaceAvailable }, { 61, SocketError.NoData }, { 2, SocketError.AddressNotAvailable }, { 92, SocketError.ProtocolOption }, { 107, SocketError.NotConnected }, { 88, SocketError.NotSocket }, { 3440, SocketError.OperationNotSupported }, { 1, SocketError.AccessDenied }, { 32, SocketError.Shutdown }, { 96, SocketError.ProtocolFamilyNotSupported }, { 93, SocketError.ProtocolNotSupported }, { 91, SocketError.ProtocolType }, { 94, SocketError.SocketNotSupported }, { 108, SocketError.Disconnecting }, { 110, SocketError.TimedOut }, { 0, SocketError.Success } }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { IsSupported = true; UnixMode = true; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { IsSupported = true; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int RecvFrom(IntPtr socketHandle, byte[] pinnedBuffer, int len, byte[] socketAddress, ref int socketAddressSize) { if (!UnixMode) { return WinSock.recvfrom(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, ref socketAddressSize); } return UnixSock.recvfrom(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, ref socketAddressSize); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static int SendTo(IntPtr socketHandle, byte* pinnedBuffer, int len, byte[] socketAddress, int socketAddressSize) { if (!UnixMode) { return WinSock.sendto(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, socketAddressSize); } return UnixSock.sendto(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, socketAddressSize); } public static SocketError GetSocketError() { int lastWin32Error = Marshal.GetLastWin32Error(); if (UnixMode) { if (!NativeErrorToSocketError.TryGetValue(lastWin32Error, out var value)) { return SocketError.SocketError; } return value; } return (SocketError)lastWin32Error; } public static SocketException GetSocketException() { int lastWin32Error = Marshal.GetLastWin32Error(); if (UnixMode) { if (!NativeErrorToSocketError.TryGetValue(lastWin32Error, out var value)) { return new SocketException(-1); } return new SocketException((int)value); } return new SocketException(lastWin32Error); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short GetNativeAddressFamily(IPEndPoint remoteEndPoint) { if (!UnixMode) { return (short)remoteEndPoint.AddressFamily; } return (short)((remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) ? 2 : 10); } } public enum NatAddressType { Internal, External } public interface INatPunchListener { void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token); void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token); } public class EventBasedNatPunchListener : INatPunchListener { public delegate void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token); public delegate void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token); public event OnNatIntroductionRequest NatIntroductionRequest; public event OnNatIntroductionSuccess NatIntroductionSuccess; void INatPunchListener.OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token) { if (this.NatIntroductionRequest != null) { this.NatIntroductionRequest(localEndPoint, remoteEndPoint, token); } } void INatPunchListener.OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token) { if (this.NatIntroductionSuccess != null) { this.NatIntroductionSuccess(targetEndPoint, type, token); } } } public sealed class NatPunchModule { private struct RequestEventData { public IPEndPoint LocalEndPoint; public IPEndPoint RemoteEndPoint; public string Token; } private struct SuccessEventData { public IPEndPoint TargetEndPoint; public NatAddressType Type; public string Token; } private class NatIntroduceRequestPacket { public IPEndPoint Internal { [Preserve] get; [Preserve] set; } public string Token { [Preserve] get; [Preserve] set; } } private class NatIntroduceResponsePacket { public IPEndPoint Internal { [Preserve] get; [Preserve] set; } public IPEndPoint External { [Preserve] get; [Preserve] set; } public string Token { [Preserve] get; [Preserve] set; } } private class NatPunchPacket { public string Token { [Preserve] get; [Preserve] set; } public bool IsExternal { [Preserve] get; [Preserve] set; } } private readonly NetManager _socket; private readonly ConcurrentQueue<RequestEventData> _requestEvents = new ConcurrentQueue<RequestEventData>(); private readonly ConcurrentQueue<SuccessEventData> _successEvents = new ConcurrentQueue<SuccessEventData>(); private readonly NetDataReader _cacheReader = new NetDataReader(); private readonly NetDataWriter _cacheWriter = new NetDataWriter(); private readonly NetPacketProcessor _netPacketProcessor = new NetPacketProcessor(256); private INatPunchListener _natPunchListener; public const int MaxTokenLength = 256; public bool UnsyncedEvents; internal NatPunchModule(NetManager socket) { _socket = socket; _netPacketProcessor.SubscribeReusable<NatIntroduceResponsePacket>(OnNatIntroductionResponse); _netPacketProcessor.SubscribeReusable<NatIntroduceRequestPacket, IPEndPoint>(OnNatIntroductionRequest); _netPacketProcessor.SubscribeReusable<NatPunchPacket, IPEndPoint>(OnNatPunch); } internal void ProcessMessage(IPEndPoint senderEndPoint, NetPacket packet) { lock (_cacheReader) { _cacheReader.SetSource(packet.RawData, 1, packet.Size); _netPacketProcessor.ReadAllPackets(_cacheReader, senderEndPoint); } } public void Init(INatPunchListener listener) { _natPunchListener = listener; } private void Send<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] T>(T packet, IPEndPoint target) where T : class, new() { _cacheWriter.Reset(); _cacheWriter.Put((byte)16); _netPacketProcessor.Write(_cacheWriter, packet); _socket.SendRaw(_cacheWriter.Data, 0, _cacheWriter.Length, target); } public void NatIntroduce(IPEndPoint hostInternal, IPEndPoint hostExternal, IPEndPoint clientInternal, IPEndPoint clientExternal, string additionalInfo) { NatIntroduceResponsePacket natIntroduceResponsePacket = new NatIntroduceResponsePacket { Token = additionalInfo }; natIntroduceResponsePacket.Internal = hostInternal; natIntroduceResponsePacket.External = hostExternal; Send(natIntroduceResponsePacket, clientExternal); natIntroduceResponsePacket.Internal = clientInternal; natIntroduceResponsePacket.External = clientExternal; Send(natIntroduceResponsePacket, hostExternal); } public void PollEvents() { if (!UnsyncedEvents && _natPunchListener != null && (!_successEvents.IsEmpty || !_requestEvents.IsEmpty)) { SuccessEventData result; while (_successEvents.TryDequeue(out result)) { _natPunchListener.OnNatIntroductionSuccess(result.TargetEndPoint, result.Type, result.Token); } RequestEventData result2; while (_requestEvents.TryDequeue(out result2)) { _natPunchListener.OnNatIntroductionRequest(result2.LocalEndPoint, result2.RemoteEndPoint, result2.Token); } } } public void SendNatIntroduceRequest(string host, int port, string additionalInfo) { SendNatIntroduceRequest(NetUtils.MakeEndPoint(host, port), additionalInfo); } public void SendNatIntroduceRequest(IPEndPoint masterServerEndPoint, string additionalInfo) { string localIp = NetUtils.GetLocalIp(LocalAddrType.IPv4); if (string.IsNullOrEmpty(localIp) || masterServerEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { localIp = NetUtils.GetLocalIp(LocalAddrType.IPv6); } Send(new NatIntroduceRequestPacket { Internal = NetUtils.MakeEndPoint(localIp, _socket.LocalPort), Token = additionalInfo }, masterServerEndPoint); } private void OnNatIntroductionRequest(NatIntroduceRequestPacket req, IPEndPoint senderEndPoint) { if (UnsyncedEvents) { _natPunchListener.OnNatIntroductionRequest(req.Internal, senderEndPoint, req.Token); return; } _requestEvents.Enqueue(new RequestEventData { LocalEndPoint = req.Internal, RemoteEndPoint = senderEndPoint, Token = req.Token }); } private void OnNatIntroductionResponse(NatIntroduceResponsePacket req) { NatPunchPacket natPunchPacket = new NatPunchPacket { Token = req.Token }; Send(natPunchPacket, req.Internal); _socket.Ttl = 2; _socket.SendRaw(new byte[1] { 17 }, 0, 1, req.External); _socket.Ttl = 255; natPunchPacket.IsExternal = true; Send(natPunchPacket, req.External); } private void OnNatPunch(NatPunchPacket req, IPEndPoint senderEndPoint) { if (UnsyncedEvents) { _natPunchListener.OnNatIntroductionSuccess(senderEndPoint, req.IsExternal ? NatAddressType.External : NatAddressType.Internal, req.Token); return; } _successEvents.Enqueue(new SuccessEventData { TargetEndPoint = senderEndPoint, Type = (req.IsExternal ? NatAddressType.External : NatAddressType.Internal), Token = req.Token }); } } public enum DeliveryMethod : byte { Unreliable = 4, ReliableUnordered = 0, Sequenced = 1, ReliableOrdered = 2, ReliableSequenced = 3 } public static class NetConstants { public const int DefaultWindowSize = 64; public const int SocketBufferSize = 1048576; public const int SocketTTL = 255; public const int HeaderSize = 1; public const int ChanneledHeaderSize = 4; public const int FragmentHeaderSize = 6; public const int FragmentedHeaderTotalSize = 10; public const ushort MaxSequence = 32768; public const ushort HalfMaxSequence = 16384; internal const int ProtocolId = 13; internal const int MaxUdpHeaderSize = 68; internal const int ChannelTypeCount = 4; internal static readonly int[] PossibleMtu = new int[6] { 1024, 1164, 1392, 1404, 1424, 1432 }; public static readonly int InitialMtu = PossibleMtu[0]; public static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1]; public static readonly int MaxUnreliableDataSize = MaxPacketSize - 1; public const byte MaxConnectionNumber = 4; } public class InvalidPacketException : ArgumentException { public InvalidPacketException(string message) : base(message) { } } public class TooBigPacketException : InvalidPacketException { public TooBigPacketException(string message) : base(message) { } } public enum NetLogLevel { Warning, Error, Trace, Info } public interface INetLogger { void WriteNet(NetLogLevel level, string str, params object[] args); } public static class NetDebug { public static INetLogger Logger = null; private static readonly object DebugLogLock = new object(); private static void WriteLogic(NetLogLevel logLevel, string str, params object[] args) { lock (DebugLogLock) { if (Logger == null) { Console.WriteLine(str, args); } else { Logger.WriteNet(logLevel, str, args); } } } [Conditional("DEBUG_MESSAGES")] internal static void Write(string str) { WriteLogic(NetLogLevel.Trace, str); } [Conditional("DEBUG_MESSAGES")] internal static void Write(NetLogLevel level, string str) { WriteLogic(level, str); } [Conditional("DEBUG_MESSAGES")] [Conditional("DEBUG")] internal static void WriteForce(string str) { WriteLogic(NetLogLevel.Trace, str); } [Conditional("DEBUG_MESSAGES")] [Conditional("DEBUG")] internal static void WriteForce(NetLogLevel level, string str) { WriteLogic(level, str); } internal static void WriteError(string str) { WriteLogic(NetLogLevel.Error, str); } } public sealed class NetPacketReader : NetDataReader { private NetPacket _packet; private readonly NetManager _manager; private readonly NetEvent _evt; internal NetPacketReader(NetManager manager, NetEvent evt) { _manager = manager; _evt = evt; } internal void SetSource(NetPacket packet, int headerSize) { if (packet != null) { _packet = packet; SetSource(packet.RawData, headerSize, packet.Size); } } internal void RecycleInternal() { Clear(); if (_packet != null) { _manager.PoolRecycle(_packet); } _packet = null; _manager.RecycleEvent(_evt); } public void Recycle() { if (!_manager.AutoRecycle) { RecycleInternal(); } } } internal sealed class NetEvent { public enum EType { Connect, Disconnect, Receive, ReceiveUnconnected, Error, ConnectionLatencyUpdated, Broadcast, ConnectionRequest, MessageDelivered, PeerAddressChanged } public NetEvent Next; public EType Type; public NetPeer Peer; public IPEndPoint RemoteEndPoint; public object UserData; public int Latency; public SocketError ErrorCode; public DisconnectReason DisconnectReason; public ConnectionRequest ConnectionRequest; public DeliveryMethod DeliveryMethod; public byte ChannelNumber; public readonly NetPacketReader DataReader; public NetEvent(NetManager manager) { DataReader = new NetPacketReader(manager, this); } } public class NetManager : IEnumerable<NetPeer>, IEnumerable { public struct NetPeerEnumerator : IEnumerator<NetPeer>, IEnumerator, IDisposable { private readonly NetPeer _initialPeer; private NetPeer _p; public NetPeer Current => _p; object IEnumerator.Current => _p; public NetPeerEnumerator(NetPeer p) { _initialPeer = p; _p = null; } public void Dispose() { } public bool MoveNext() { _p = ((_p == null) ? _initialPeer : _p.NextPeer); return _p != null; } public void Reset() { throw new NotSupportedException(); } } private struct IncomingData { public NetPacket Data; public IPEndPoint EndPoint; public DateTime TimeWhenGet; } private struct Slot { internal int HashCode; internal int Next; internal NetPeer Value; } private readonly List<IncomingData> _pingSimulationList = new List<IncomingData>(); private readonly Random _randomGenerator = new Random(); private const int MinLatencyThreshold = 5; private Thread _logicThread; private bool _manualMode; private readonly AutoResetEvent _updateTriggerEvent = new AutoResetEvent(initialState: true); private NetEvent _pendingEventHead; private NetEvent _pendingEventTail; private NetEvent _netEventPoolHead; private readonly INetEventListener _netEventListener; private readonly IDeliveryEventListener _deliveryEventListener; private readonly INtpEventListener _ntpEventListener; private readonly IPeerAddressChangedListener _peerAddressChangedListener; private readonly Dictionary<IPEndPoint, ConnectionRequest> _requestsDict = new Dictionary<IPEndPoint, ConnectionRequest>(); private readonly ConcurrentDictionary<IPEndPoint, NtpRequest> _ntpRequests = new ConcurrentDictionary<IPEndPoint, NtpRequest>(); private long _connectedPeersCount; private readonly List<NetPeer> _connectedPeerListCache = new List<NetPeer>(); private readonly PacketLayerBase _extraPacketLayer; private int _lastPeerId; private ConcurrentQueue<int> _peerIds = new ConcurrentQueue<int>(); private byte _channelsCount = 1; private readonly object _eventLock = new object(); private bool _dropPacket; public bool UnconnectedMessagesEnabled; public bool NatPunchEnabled; public int UpdateTime = 15; public int PingInterval = 1000; public int DisconnectTimeout = 5000; public bool SimulatePacketLoss; public bool SimulateLatency; public int SimulationPacketLossChance = 10; public int SimulationMinLatency = 30; public int SimulationMaxLatency = 100; public bool UnsyncedEvents; public bool UnsyncedReceiveEvent; public bool UnsyncedDeliveryEvent; public bool BroadcastReceiveEnabled; public int ReconnectDelay = 500; public int MaxConnectAttempts = 10; public bool ReuseAddress; public bool DontRoute; public readonly NetStatistics Statistics = new NetStatistics(); public bool EnableStatistics; public readonly NatPunchModule NatPunchModule; public bool AutoRecycle; public bool IPv6Enabled = true; public int MtuOverride; public bool MtuDiscovery; public bool UseNativeSockets; public bool DisconnectOnUnreachable; public bool AllowPeerAddressChange; private const int MaxPrimeArrayLength = 2147483587; private const int HashPrime = 101; private const int Lower31BitMask = int.MaxValue; private static readonly int[] Primes; private int[] _buckets; private Slot[] _slots; private int _count; private int _lastIndex; private int _freeList = -1; private NetPeer[] _peersArray = new NetPeer[32]; private readonly ReaderWriterLockSlim _peersLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); private volatile NetPeer _headPeer; private NetPacket _poolHead; private int _poolCount; private readonly object _poolLock = new object(); public int PacketPoolSize = 1000; private const int ReceivePollingTime = 500000; private Socket _udpSocketv4; private Socket _udpSocketv6; private Thread _receiveThread; private IPEndPoint _bufferEndPointv4; private IPEndPoint _bufferEndPointv6; private const int SioUdpConnreset = -1744830452; private static readonly IPAddress MulticastAddressV6; public static readonly bool IPv6Support; internal bool NotConnected; public bool IsRunning { get; private set; } public int LocalPort { get; private set; } public NetPeer FirstPeer => _headPeer; public byte ChannelsCount { get { return _channelsCount; } set { if (value < 1 || value > 64) { throw new ArgumentException("Channels count must be between 1 and 64"); } _channelsCount = value; } } public List<NetPeer> ConnectedPeerList { get { GetPeersNonAlloc(_connectedPeerListCache, ConnectionState.Connected); return _connectedPeerListCache; } } public int ConnectedPeersCount => (int)Interlocked.Read(ref _connectedPeersCount); public int ExtraPacketSizeForLayer => _extraPacketLayer?.ExtraPacketSizeForLayer ?? 0; public int PoolCount => _poolCount; public short Ttl { get { return _udpSocketv4.Ttl; } internal set { _udpSocketv4.Ttl = value; } } public NetManager(INetEventListener listener, PacketLayerBase extraPacketLayer = null) { _netEventListener = listener; _deliveryEventListener = listener as IDeliveryEventListener; _ntpEventListener = listener as INtpEventListener; _peerAddressChangedListener = listener as IPeerAddressChangedListener; NatPunchModule = new NatPunchModule(this); _extraPacketLayer = extraPacketLayer; } internal void ConnectionLatencyUpdated(NetPeer fromPeer, int latency) { CreateEvent(NetEvent.EType.ConnectionLatencyUpdated, fromPeer, null, SocketError.Success, latency, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } internal void MessageDelivered(NetPeer fromPeer, object userData) { if (_deliveryEventListener != null) { CreateEvent(NetEvent.EType.MessageDelivered, fromPeer, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, null, userData); } } internal void DisconnectPeerForce(NetPeer peer, DisconnectReason reason, SocketError socketErrorCode, NetPacket eventData) { DisconnectPeer(peer, reason, socketErrorCode, force: true, null, 0, 0, eventData); } private void DisconnectPeer(NetPeer peer, DisconnectReason reason, SocketError socketErrorCode, bool force, byte[] data, int start, int count, NetPacket eventData) { switch (peer.Shutdown(data, start, count, force)) { case ShutdownResult.None: return; case ShutdownResult.WasConnected: Interlocked.Decrement(ref _connectedPeersCount); break; } CreateEvent(NetEvent.EType.Disconnect, peer, null, socketErrorCode, 0, reason, null, DeliveryMethod.Unreliable, 0, eventData); } private void CreateEvent(NetEvent.EType type, NetPeer peer = null, IPEndPoint remoteEndPoint = null, SocketError errorCode = SocketError.Success, int latency = 0, DisconnectReason disconnectReason = DisconnectReason.ConnectionFailed, ConnectionRequest connectionRequest = null, DeliveryMethod deliveryMethod = DeliveryMethod.Unreliable, byte channelNumber = 0, NetPacket readerSource = null, object userData = null) { bool flag = UnsyncedEvents; switch (type) { case NetEvent.EType.Connect: Interlocked.Increment(ref _connectedPeersCount); break; case NetEvent.EType.MessageDelivered: flag = UnsyncedDeliveryEvent; break; } NetEvent netEvent; lock (_eventLock) { netEvent = _netEventPoolHead; if (netEvent == null) { netEvent = new NetEvent(this); } else { _netEventPoolHead = netEvent.Next; } } netEvent.Next = null; netEvent.Type = type; netEvent.DataReader.SetSource(readerSource, readerSource?.GetHeaderSize() ?? 0); netEvent.Peer = peer; netEvent.RemoteEndPoint = remoteEndPoint; netEvent.Latency = latency; netEvent.ErrorCode = errorCode; netEvent.DisconnectReason = disconnectReason; netEvent.ConnectionRequest = connectionRequest; netEvent.DeliveryMethod = deliveryMethod; netEvent.ChannelNumber = channelNumber; netEvent.UserData = userData; if (flag || _manualMode) { ProcessEvent(netEvent); return; } lock (_eventLock) { if (_pendingEventTail == null) { _pendingEventHead = netEvent; } else { _pendingEventTail.Next = netEvent; } _pendingEventTail = netEvent; } } private void ProcessEvent(NetEvent evt) { bool isNull = evt.DataReader.IsNull; switch (evt.Type) { case NetEvent.EType.Connect: _netEventListener.OnPeerConnected(evt.Peer); break; case NetEvent.EType.Disconnect: { DisconnectInfo disconnectInfo = default(DisconnectInfo); disconnectInfo.Reason = evt.DisconnectReason; disconnectInfo.AdditionalData = evt.DataReader; disconnectInfo.SocketErrorCode = evt.ErrorCode; DisconnectInfo disconnectInfo2 = disconnectInfo; _netEventListener.OnPeerDisconnected(evt.Peer, disconnectInfo2); break; } case NetEvent.EType.Receive: _netEventListener.OnNetworkReceive(evt.Peer, evt.DataReader, evt.ChannelNumber, evt.DeliveryMethod); break; case NetEvent.EType.ReceiveUnconnected: _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.BasicMessage); break; case NetEvent.EType.Broadcast: _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.Broadcast); break; case NetEvent.EType.Error: _netEventListener.OnNetworkError(evt.RemoteEndPoint, evt.ErrorCode); break; case NetEvent.EType.ConnectionLatencyUpdated: _netEventListener.OnNetworkLatencyUpdate(evt.Peer, evt.Latency); break; case NetEvent.EType.ConnectionRequest: _netEventListener.OnConnectionRequest(evt.ConnectionRequest); break; case NetEvent.EType.MessageDelivered: _deliveryEventListener.OnMessageDelivered(evt.Peer, evt.UserData); break; case NetEvent.EType.PeerAddressChanged: { _peersLock.EnterUpgradeableReadLock(); IPEndPoint iPEndPoint = null; if (ContainsPeer(evt.Peer)) { _peersLock.EnterWriteLock(); RemovePeerFromSet(evt.Peer); iPEndPoint = new IPEndPoint(evt.Peer.Address, evt.Peer.Port); evt.Peer.FinishEndPointChange(evt.RemoteEndPoint); AddPeerToSet(evt.Peer); _peersLock.ExitWriteLock(); } _peersLock.ExitUpgradeableReadLock(); if (iPEndPoint != null && _peerAddressChangedListener != null) { _peerAddressChangedListener.OnPeerAddressChanged(evt.Peer, iPEndPoint); } break; } } if (isNull) { RecycleEvent(evt); } else if (AutoRecycle) { evt.DataReader.RecycleInternal(); } } internal void RecycleEvent(NetEvent evt) { evt.Peer = null; evt.ErrorCode = SocketError.Success; evt.RemoteEndPoint = null; evt.ConnectionRequest = null; lock (_eventLock) { evt.Next = _netEventPoolHead; _netEventPoolHead = evt; } } private void UpdateLogic() { List<NetPeer> list = new List<NetPeer>(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (IsRunning) { try { float num = (float)((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0); num = ((num <= 0f) ? 0.001f : num); stopwatch.Restart(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > (float)DisconnectTimeout) { list.Add(netPeer); } else { netPeer.Update(num); } } if (list.Count > 0) { _peersLock.EnterWriteLock(); for (int i = 0; i < list.Count; i++) { RemovePeer(list[i], enableWriteLock: false); } _peersLock.ExitWriteLock(); list.Clear(); } ProcessNtpRequests(num); int num2 = UpdateTime - (int)stopwatch.ElapsedMilliseconds; if (num2 > 0) { _updateTriggerEvent.WaitOne(num2); } } catch (ThreadAbortException) { return; } catch (Exception ex2) { NetDebug.WriteError("[NM] LogicThread error: " + ex2); } } stopwatch.Stop(); } [Conditional("DEBUG")] private void ProcessDelayedPackets() { if (!SimulateLatency) { return; } DateTime utcNow = DateTime.UtcNow; lock (_pingSimulationList) { for (int i = 0; i < _pingSimulationList.Count; i++) { IncomingData incomingData = _pingSimulationList[i]; if (incomingData.TimeWhenGet <= utcNow) { HandleMessageReceived(incomingData.Data, incomingData.EndPoint); _pingSimulationList.RemoveAt(i); i--; } } } } private void ProcessNtpRequests(float elapsedMilliseconds) { List<IPEndPoint> list = null; foreach (KeyValuePair<IPEndPoint, NtpRequest> ntpRequest in _ntpRequests) { ntpRequest.Value.Send(_udpSocketv4, elapsedMilliseconds); if (ntpRequest.Value.NeedToKill) { if (list == null) { list = new List<IPEndPoint>(); } list.Add(ntpRequest.Key); } } if (list == null) { return; } foreach (IPEndPoint item in list) { _ntpRequests.TryRemove(item, out var _); } } public void ManualUpdate(float elapsedMilliseconds) { if (!_manualMode) { return; } for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > (float)DisconnectTimeout) { RemovePeer(netPeer, enableWriteLock: false); } else { netPeer.Update(elapsedMilliseconds); } } ProcessNtpRequests(elapsedMilliseconds); } internal NetPeer OnConnectionSolved(ConnectionRequest request, byte[] rejectData, int start, int length) { NetPeer actualValue = null; if (request.Result == ConnectionRequestResult.RejectForce) { if (rejectData != null && length > 0) { NetPacket netPacket = PoolGetWithProperty(PacketProperty.Disconnect, length); netPacket.ConnectionNumber = request.InternalPacket.ConnectionNumber; FastBitConverter.GetBytes(netPacket.RawData, 1, request.InternalPacket.ConnectionTime); if (netPacket.Size >= NetConstants.PossibleMtu[0]) { NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU!"); } else { Buffer.BlockCopy(rejectData, start, netPacket.RawData, 9, length); } SendRawAndRecycle(netPacket, request.RemoteEndPoint); } lock (_requestsDict) { _requestsDict.Remove(request.RemoteEndPoint); } } else { lock (_requestsDict) { if (!TryGetPeer(request.RemoteEndPoint, out actualValue)) { if (request.Result == ConnectionRequestResult.Reject) { actualValue = new NetPeer(this, request.RemoteEndPoint, GetNextPeerId()); actualValue.Reject(request.InternalPacket, rejectData, start, length); AddPeer(actualValue); } else { actualValue = new NetPeer(this, request, GetNextPeerId()); AddPeer(actualValue); CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } } _requestsDict.Remove(request.RemoteEndPoint); } } return actualValue; } private int GetNextPeerId() { if (!_peerIds.TryDequeue(out var result)) { return _lastPeerId++; } return result; } private void ProcessConnectRequest(IPEndPoint remoteEndPoint, NetPeer netPeer, NetConnectRequestPacket connRequest) { if (netPeer != null) { ConnectRequestResult connectRequestResult = netPeer.ProcessConnectRequest(connRequest); switch (connectRequestResult) { default: return; case ConnectRequestResult.Reconnection: DisconnectPeerForce(netPeer, DisconnectReason.Reconnect, SocketError.Success, null); RemovePeer(netPeer, enableWriteLock: true); break; case ConnectRequestResult.NewConnection: RemovePeer(netPeer, enableWriteLock: true); break; case ConnectRequestResult.P2PLose: DisconnectPeerForce(netPeer, DisconnectReason.PeerToPeerConnection, SocketError.Success, null); RemovePeer(netPeer, enableWriteLock: true); break; } if (connectRequestResult != ConnectRequestResult.P2PLose) { connRequest.ConnectionNumber = (byte)((netPeer.ConnectionNum + 1) % 4); } } ConnectionRequest value; lock (_requestsDict) { if (_requestsDict.TryGetValue(remoteEndPoint, out value)) { value.UpdateRequest(connRequest); return; } value = new ConnectionRequest(remoteEndPoint, connRequest, this); _requestsDict.Add(remoteEndPoint, value); } CreateEvent(NetEvent.EType.ConnectionRequest, null, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, value, DeliveryMethod.Unreliable, 0); } private void OnMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) { if (packet.Size == 0) { PoolRecycle(packet); return; } _dropPacket = false; if (!_dropPacket) { HandleMessageReceived(packet, remoteEndPoint); } } [Conditional("DEBUG")] private void HandleSimulateLatency(NetPacket packet, IPEndPoint remoteEndPoint) { if (!SimulateLatency) { return; } int num = _randomGenerator.Next(SimulationMinLatency, SimulationMaxLatency); if (num > 5) { lock (_pingSimulationList) { _pingSimulationList.Add(new IncomingData { Data = packet, EndPoint = remoteEndPoint, TimeWhenGet = DateTime.UtcNow.AddMilliseconds(num) }); } _dropPacket = true; } } [Conditional("DEBUG")] private void HandleSimulatePacketLoss() { if (SimulatePacketLoss && _randomGenerator.NextDouble() * 100.0 < (double)SimulationPacketLossChance) { _dropPacket = true; } } private void HandleMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) { int size = packet.Size; if (EnableStatistics) { Statistics.IncrementPacketsReceived(); Statistics.AddBytesReceived(size); } if (_ntpRequests.Count > 0 && _ntpRequests.TryGetValue(remoteEndPoint, out var _)) { if (packet.Size >= 48) { byte[] array = new byte[packet.Size]; Buffer.BlockCopy(packet.RawData, 0, array, 0, packet.Size); NtpPacket ntpPacket = NtpPacket.FromServerResponse(array, DateTime.UtcNow); try { ntpPacket.ValidateReply(); } catch (InvalidOperationException) { ntpPacket = null; } if (ntpPacket != null) { _ntpRequests.TryRemove(remoteEndPoint, out var _); _ntpEventListener?.OnNtpResponse(ntpPacket); } } return; } if (_extraPacketLayer != null) { _extraPacketLayer.ProcessInboundPacket(ref remoteEndPoint, ref packet.RawData, ref packet.Size); if (packet.Size == 0) { return; } } if (!packet.Verify()) { NetDebug.WriteError("[NM] DataReceived: bad!"); PoolRecycle(packet); return; } switch (packet.Property) { case PacketProperty.ConnectRequest: if (NetConnectRequestPacket.GetProtocolId(packet) != 13) { SendRawAndRecycle(PoolGetWithProperty(PacketProperty.InvalidProtocol), remoteEndPoint); return; } break; case PacketProperty.Broadcast: if (BroadcastReceiveEnabled) { CreateEvent(NetEvent.EType.Broadcast, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet); } return; case PacketProperty.UnconnectedMessage: if (UnconnectedMessagesEnabled) { CreateEvent(NetEvent.EType.ReceiveUnconnected, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet); } return; case PacketProperty.NatMessage: if (NatPunchEnabled) { NatPunchModule.ProcessMessage(remoteEndPoint, packet); } return; } NetPeer actualValue = remoteEndPoint as NetPeer; bool flag = actualValue != null || TryGetPeer(remoteEndPoint, out actualValue); if (flag && EnableStatistics) { actualValue.Statistics.IncrementPacketsReceived(); actualValue.Statistics.AddBytesReceived(size); } switch (packet.Property) { case PacketProperty.ConnectRequest: { NetConnectRequestPacket netConnectRequestPacket = NetConnectRequestPacket.FromData(packet); if (netConnectRequestPacket != null) { ProcessConnectRequest(remoteEndPoint, actualValue, netConnectRequestPacket); } break; } case PacketProperty.PeerNotFound: if (flag) { if (actualValue.ConnectionState == ConnectionState.Connected) { if (packet.Size == 1) { actualValue.ResetMtu(); SendRaw(NetConnectAcceptPacket.MakeNetworkChanged(actualValue), remoteEndPoint); } else if (packet.Size == 2 && packet.RawData[1] == 1) { DisconnectPeerForce(actualValue, DisconnectReason.PeerNotFound, SocketError.Success, null); } } } else { if (packet.Size <= 1) { break; } bool flag2 = false; if (AllowPeerAddressChange) { NetConnectAcceptPacket netConnectAcceptPacket = NetConnectAcceptPacket.FromData(packet); if (netConnectAcceptPacket != null && netConnectAcceptPacket.PeerNetworkChanged && netConnectAcceptPacket.PeerId < _peersArray.Length) { _peersLock.EnterUpgradeableReadLock(); NetPeer netPeer = _peersArray[netConnectAcceptPacket.PeerId]; _peersLock.ExitUpgradeableReadLock(); if (netPeer != null && netPeer.ConnectTime == netConnectAcceptPacket.ConnectionTime && netPeer.ConnectionNum == netConnectAcceptPacket.ConnectionNumber) { if (netPeer.ConnectionState == ConnectionState.Connected) { netPeer.InitiateEndPointChange(); CreateEvent(NetEvent.EType.PeerAddressChanged, netPeer, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } flag2 = true; } } } PoolRecycle(packet); if (!flag2) { NetPacket netPacket = PoolGetWithProperty(PacketProperty.PeerNotFound, 1); netPacket.RawData[1] = 1; SendRawAndRecycle(netPacket, remoteEndPoint); } } break; case PacketProperty.InvalidProtocol: if (flag && actualValue.ConnectionState == ConnectionState.Outgoing) { DisconnectPeerForce(actualValue, DisconnectReason.InvalidProtocol, SocketError.Success, null); } break; case PacketProperty.Disconnect: if (flag) { DisconnectResult disconnectResult = actualValue.ProcessDisconnect(packet); if (disconnectResult == DisconnectResult.None) { PoolRecycle(packet); break; } DisconnectPeerForce(actualValue, (disconnectResult == DisconnectResult.Disconnect) ? DisconnectReason.RemoteConnectionClose : DisconnectReason.ConnectionRejected, SocketError.Success, packet); } else { PoolRecycle(packet); } SendRawAndRecycle(PoolGetWithProperty(PacketProperty.ShutdownOk), remoteEndPoint); break; case PacketProperty.ConnectAccept: if (flag) { NetConnectAcceptPacket netConnectAcceptPacket2 = NetConnectAcceptPacket.FromData(packet); if (netConnectAcceptPacket2 != null && actualValue.ProcessConnectAccept(netConnectAcceptPacket2)) { CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } } break; default: if (flag) { actualValue.ProcessPacket(packet); } else { SendRawAndRecycle(PoolGetWithProperty(PacketProperty.PeerNotFound), remoteEndPoint); } break; } } internal void CreateReceiveEvent(NetPacket packet, DeliveryMethod method, byte channelNumber, int headerSize, NetPeer fromPeer) { if (UnsyncedEvents || UnsyncedReceiveEvent || _manualMode) { NetEvent netEvent; lock (_eventLock) { netEvent = _netEventPoolHead; if (netEvent == null) { netEvent = new NetEvent(this); } else { _netEventPoolHead = netEvent.Next; } } netEvent.Next = null; netEvent.Type = NetEvent.EType.Receive; netEvent.DataReader.SetSource(packet, headerSize); netEvent.Peer = fromPeer; netEvent.DeliveryMethod = method; netEvent.ChannelNumber = channelNumber; ProcessEvent(netEvent); return; } lock (_eventLock) { NetEvent netEvent = _netEventPoolHead; if (netEvent == null) { netEvent = new NetEvent(this); } else { _netEventPoolHead = netEvent.Next; } netEvent.Next = null; netEvent.Type = NetEvent.EType.Receive; netEvent.DataReader.SetSource(packet, headerSize); netEvent.Peer = fromPeer; netEvent.DeliveryMethod = method; netEvent.ChannelNumber = channelNumber; if (_pendingEventTail == null) { _pendingEventHead = netEvent; } else { _pendingEventTail.Next = netEvent; } _pendingEventTail = netEvent; } } public void SendToAll(NetDataWriter writer, DeliveryMethod options) { SendToAll(writer.Data, 0, writer.Length, options); } public void SendToAll(byte[] data, DeliveryMethod options) { SendToAll(data, 0, data.Length, options); } public void SendToAll(byte[] data, int start, int length, DeliveryMethod options) { SendToAll(data, start, length, 0, options); } public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options) { SendToAll(writer.Data, 0, writer.Length, channelNumber, options); } public void SendToAll(byte[] data, byte channelNumber, DeliveryMethod options) { SendToAll(data, 0, data.Length, channelNumber, options); } public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options) { try { _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { netPeer.Send(data, start, length, channelNumber, options); } } finally { _peersLock.ExitReadLock(); } } public void SendToAll(NetDataWriter writer, DeliveryMethod options, NetPeer excludePeer) { SendToAll(writer.Data, 0, writer.Length, 0, options, excludePeer); } public void SendToAll(byte[] data, DeliveryMethod options, NetPeer excludePeer) { SendToAll(data, 0, data.Length, 0, options, excludePeer); } public void SendToAll(byte[] data, int start, int length, DeliveryMethod options, NetPeer excludePeer) { SendToAll(data, start, length, 0, options, excludePeer); } public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) { SendToAll(writer.Data, 0, writer.Length, channelNumber, options, excludePeer); } public void SendToAll(byte[] data, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) { SendToAll(data, 0, data.Length, channelNumber, options, excludePeer); } public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) { try { _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if (netPeer != excludePeer) { netPeer.Send(data, start, length, channelNumber, options); } } } finally { _peersLock.ExitReadLock(); } } public void SendToAll(ReadOnlySpan<byte> data, DeliveryMethod options) { SendToAll(data, 0, options, null); } public void SendToAll(ReadOnlySpan<byte> data, DeliveryMethod options, NetPeer excludePeer) { SendToAll(data, 0, options, excludePeer); } public void SendToAll(ReadOnlySpan<byte> data, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) { try { _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if (netPeer != excludePeer) { netPeer.Send(data, channelNumber, options); } } } finally { _peersLock.ExitReadLock(); } } public bool SendUnconnectedMessage(ReadOnlySpan<byte> message, IPEndPoint remoteEndPoint) { int headerSize = NetPacket.GetHeaderSize(PacketProperty.UnconnectedMessage); NetPacket netPacket = PoolGetPacket(message.Length + headerSize); netPacket.Property = PacketProperty.UnconnectedMessage; message.CopyTo(new Span<byte>(netPacket.RawData, headerSize, message.Length)); return SendRawAndRecycle(netPacket, remoteEndPoint) > 0; } public bool Start() { return Start(0); } public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port) { return Start(addressIPv4, addressIPv6, port, manualMode: false); } public bool Start(string addressIPv4, string addressIPv6, int port) { IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4); IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6); return Start(addressIPv7, addressIPv8, port); } public bool Start(int port) { return Start(IPAddress.Any, IPAddress.IPv6Any, port); } public bool StartInManualMode(IPAddress addressIPv4, IPAddress addressIPv6, int port) { return Start(addressIPv4, addressIPv6, port, manualMode: true); } public bool StartInManualMode(string addressIPv4, string addressIPv6, int port) { IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4); IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6); return StartInManualMode(addressIPv7, addressIPv8, port); } public bool StartInManualMode(int port) { return StartInManualMode(IPAddress.Any, IPAddress.IPv6Any, port); } public bool SendUnconnectedMessage(byte[] message, IPEndPoint remoteEndPoint) { return SendUnconnectedMessage(message, 0, message.Length, remoteEndPoint); } public bool SendUnconnectedMessage(NetDataWriter writer, string address, int port) { IPEndPoint remoteEndPoint = NetUtils.MakeEndPoint(address, port); return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint); } public bool SendUnconnectedMessage(NetDataWriter writer, IPEndPoint remoteEndPoint) { return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint); } public bool SendUnconnectedMessage(byte[] message, int start, int length, IPEndPoint remoteEndPoint) { NetPacket packet = PoolGetWithData(PacketProperty.UnconnectedMessage, message, start, length); return SendRawAndRecycle(packet, remoteEndPoint) > 0; } public void TriggerUpdate() { _updateTriggerEvent.Set(); } public void PollEvents(int maxProcessedEvents = 0) { if (_manualMode) { if (_udpSocketv4 != null) { ManualReceive(_udpSocketv4, _bufferEndPointv4, maxProcessedEvents); } if (_udpSocketv6 != null && _udpSocketv6 != _udpSocketv4) { ManualReceive(_udpSocketv6, _bufferEndPointv6, maxProcessedEvents); } } else { if (UnsyncedEvents) { return; } NetEvent netEvent; lock (_eventLock) { netEvent = _pendingEventHead; _pendingEventHead = null; _pendingEventTail = null; } int num = 0; while (netEvent != null) { NetEvent next = netEvent.Next; ProcessEvent(netEvent); netEvent = next; num++; if (num == maxProcessedEvents) { break; } } } } public NetPeer Connect(string address, int port, string key) { return Connect(address, port, NetDataWriter.FromString(key)); } public NetPeer Connect(string address, int port, NetDataWriter connectionData) { IPEndPoint target; try { target = NetUtils.MakeEndPoint(address, port); } catch { CreateEvent(NetEvent.EType.Disconnect, null, null, SocketError.Success, 0, DisconnectReason.UnknownHost, null, DeliveryMethod.Unreliable, 0); return null; } return Connect(target, connectionData); } public NetPeer Connect(IPEndPoint target, string key) { return Connect(target, NetDataWriter.FromString(key)); } public NetPeer Connect(IPEndPoint target, NetDataWriter connectionData) { if (!IsRunning) { throw new InvalidOperationException("Client is not running"); } lock (_requestsDict) { if (_requestsDict.ContainsKey(target)) { return null; } byte connectNum = 0; if (TryGetPeer(target, out var actualValue)) { ConnectionState connectionState = actualValue.ConnectionState; if (connectionState == ConnectionState.Outgoing || connectionState == ConnectionState.Connected) { return actualValue; } connectNum = (byte)((actualValue.ConnectionNum + 1) % 4); RemovePeer(actualValue, enableWriteLock: true); } actualValue = new NetPeer(this, target, GetNextPeerId(), connectNum, connectionData); AddPeer(actualValue); return actualValue; } } public void Stop() { Stop(sendDisconnectMessages: true); } public void Stop(bool sendDisconnectMessages) { if (IsRunning) { for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { netPeer.Shutdown(null, 0, 0, !sendDisconnectMessages); } CloseSocket(); _updateTriggerEvent.Set(); if (!_manualMode) { _logicThread.Join(); _logicThread = null; } ClearPeerSet(); _peerIds = new ConcurrentQueue<int>(); _lastPeerId = 0; _connectedPeersCount = 0L; _pendingEventHead = null; _pendingEventTail = null; } } [Conditional("DEBUG")] private void ClearPingSimulationList() { lock (_pingSimulationList) { _pingSimulationList.Clear(); } } public int GetPeersCount(ConnectionState peerState) { int num = 0; _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if ((netPeer.ConnectionState & peerState) != 0) { num++; } } _peersLock.ExitReadLock(); return num; } public void GetPeersNonAlloc(List<NetPeer> peers, ConnectionState peerState) { peers.Clear(); _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if ((netPeer.ConnectionState & peerState) != 0) { peers.Add(netPeer); } } _peersLock.ExitReadLock(); } public void DisconnectAll() { DisconnectAll(null, 0, 0); } public void DisconnectAll(byte[] data, int start, int count) { _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { DisconnectPeer(netPeer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null); } _peersLock.ExitReadLock(); } public void DisconnectPeerForce(NetPeer peer) { DisconnectPeerForce(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, null); } public void DisconnectPeer(NetPeer peer) { DisconnectPeer(peer, null, 0, 0); } public void DisconnectPeer(NetPeer peer, byte[] data) { DisconnectPeer(peer, data, 0, data.Length); } public void DisconnectPeer(NetPeer peer, NetDataWriter writer) { DisconnectPeer(peer, writer.Data, 0, writer.Length); } public void DisconnectPeer(NetPeer peer, byte[] data, int start, int count) { DisconnectPeer(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null); } public void CreateNtpRequest(IPEndPoint endPoint) { _ntpRequests.TryAdd(endPoint, new NtpRequest(endPoint)); } public void CreateNtpRequest(string ntpServerAddress, int port) { IPEndPoint iPEndPoint = NetUtils.MakeEndPoint(ntpServerAddress, port); _ntpRequests.TryAdd(iPEndPoint, new NtpRequest(iPEndPoint)); } public void CreateNtpRequest(string ntpServerAddress) { IPEndPoint iPEndPoint = NetUtils.MakeEndPoint(ntpServerAddress, 123); _ntpRequests.TryAdd(iPEndPoint, new NtpRequest(iPEndPoint)); } public NetPeerEnumerator GetEnumerator() { return new NetPeerEnumerator(_headPeer); } IEnumerator<NetPeer> IEnumerable<NetPeer>.GetEnumerator() { return new NetPeerEnumerator(_headPeer); } IEnumerator IEnumerable.GetEnumerator() { return new NetPeerEnumerator(_headPeer); } private static int HashSetGetPrime(int min) { int[] primes = Primes; foreach (int num in primes) { if (num >= min) { return num; } } for (int j = min | 1; j < int.MaxValue; j += 2) { if (IsPrime(j) && (j - 1) % 101 != 0) { return j; } } return min; static bool IsPrime(int candidate) { if (((uint)candidate & (true ? 1u : 0u)) != 0) { int num2 = (int)Math.Sqrt(candidate); for (int k = 3; k <= num2; k += 2) { if (candidate % k == 0) { return false; } } return true; } return candidate == 2; } } private void ClearPeerSet() { _peersLock.EnterWriteLock(); _headPeer = null; if (_lastIndex > 0) { Array.Clear(_slots, 0, _lastIndex); Array.Clear(_buckets, 0, _buckets.Length); _lastIndex = 0; _count = 0; _freeList = -1; } _peersArray = new NetPeer[32]; _peersLock.ExitWriteLock(); } private bool ContainsPeer(NetPeer item) { if (item == null) { NetDebug.WriteError($"Contains peer null: {item}"); return false; } if (_buckets != null) { int num = item.GetHashCode() & 0x7FFFFFFF; for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next) { if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(item)) { return true; } } } return false; } public NetPeer GetPeerById(int id) { if (id < 0 || id >= _peersArray.Length) { return null; } return _peersArray[id]; } public bool TryGetPeerById(int id, out NetPeer peer) { peer = GetPeerById(id); return peer != null; } private void AddPeer(NetPeer peer) { if (peer == null) { NetDebug.WriteError($"Add peer null: {peer}"); return; } _peersLock.EnterWriteLock(); if (_headPeer != null) { peer.NextPeer = _headPeer; _headPeer.PrevPeer = peer; } _headPeer = peer; AddPeerToSet(peer); if (peer.Id >= _peersArray.Length) { int num = _peersArray.Length * 2; while (peer.Id >= num) { num *= 2; } Array.Resize(ref _peersArray, num); } _peersArray[peer.Id] = peer; _peersLock.ExitWriteLock(); } private void RemovePeer(NetPeer peer, bool enableWriteLock) { if (enableWriteLock) { _peersLock.EnterWriteLock(); } if (!RemovePeerFromSet(peer)) { if (enableWriteLock) { _peersLock.ExitWriteLock(); } return; } if (peer == _headPeer) { _headPeer = peer.NextPeer; } if (peer.PrevPeer != null) { peer.PrevPeer.NextPeer = peer.NextPeer; } if (peer.NextPeer != null) { peer.NextPeer.PrevPeer = peer.PrevPeer; } peer.PrevPeer = null; _peersArray[peer.Id] = null; _peerIds.Enqueue(peer.Id); if (enableWriteLock) { _peersLock.ExitWriteLock(); } } private bool RemovePeerFromSet(NetPeer peer) { if (_buckets == null || peer == null) { return false; } int num = peer.GetHashCode() & 0x7FFFFFFF; int num2 = num % _buckets.Length; int num3 = -1; for (int num4 = _buckets[num2] - 1; num4 >= 0; num4 = _slots[num4].Next) { if (_slots[num4].HashCode == num && _slots[num4].Value.Equals(peer)) { if (num3 < 0) { _buckets[num2] = _slots[num4].Next + 1; } else { _slots[num3].Next = _slots[num4].Next; } _slots[num4].HashCode = -1; _slots[num4].Value = null; _slots[num4].Next = _freeList; _count--; if (_count == 0) { _lastIndex = 0; _freeList = -1; } else { _freeList = num4; } return true; } num3 = num4; } return false; } private bool TryGetPeer(IPEndPoint endPoint, out NetPeer actualValue) { if (_buckets != null) { int num = endPoint.GetHashCode() & 0x7FFFFFFF; _peersLock.EnterReadLock(); for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next) { if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(endPoint)) { actualValue = _slots[num2].Value; _peersLock.ExitReadLock(); return true; } } _peersLock.ExitReadLock(); } actualValue = null; return false; } private bool TryGetPeer(SocketAddress saddr, out NetPeer actualValue) { if (_buckets != null) { int num = saddr.GetHashCode() & 0x7FFFFFFF; _peersLock.EnterReadLock(); for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next) { if (_slots[num2].HashCode == num && _slots[num2].Value.Serialize().Equals(saddr)) { actualValue = _slots[num2].Value; _peersLock.ExitReadLock(); return true; } } _peersLock.ExitReadLock(); } actualValue = null; return false; } private bool AddPeerToSet(NetPeer value) { if (_buckets == null) { int num = HashSetGetPrime(0); _buckets = new int[num]; _slots = new Slot[num]; } int num2 = value.GetHashCode() & 0x7FFFFFFF; int num3 = num2 % _buckets.Length; for (int num4 = _buckets[num2 % _buckets.Length] - 1; num4 >= 0; num4 = _slots[num4].Next) { if (_slots[num4].HashCode == num2 && _slots[num4].Value.Equals(value)) { return false; } } int num5; if (_freeList >= 0) { num5 = _freeList; _freeList = _slots[num5].Next; } else { if (_lastIndex == _slots.Length) { int num6 = 2 * _count; num6 = (((uint)num6 > 2147483587u && 2147483587 > _count) ? 2147483587 : HashSetGetPrime(num6)); Slot[] array = new Slot[num6]; Array.Copy(_slots, 0, array, 0, _lastIndex); _buckets = new int[num6]; for (int i = 0; i < _lastIndex; i++) { int num7 = array[i].HashCode % num6; array[i].Next = _buckets[num7] - 1; _buckets[num7] = i + 1; } _slots = array; num3 = num2 % _buckets.Length; } num5 = _lastIndex; _lastIndex++; } _slots[num5].HashCode = num2; _slots[num5].Value = value; _slots[num5].Next = _buckets[num3] - 1; _buckets[num3] = num5 + 1; _count++; return true; } private NetPacket PoolGetWithData(PacketProperty property, byte[] data, int start, int length) { int headerSize = NetPacket.GetHeaderSize(property); NetPacket netPacket = PoolGetPacket(length + headerSize); netPacket.Property = property; Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length); return netPacket; } private NetPacket PoolGetWithProperty(PacketProperty property, int size) { NetPacket netPacket = PoolGetPacket(size + NetPacket.GetHeaderSize(property)); netPacket.Property = property; return netPacket; } private NetPacket PoolGetWithProperty(PacketProperty property) { NetPacket netPacket = PoolGetPacket(NetPacket.GetHeaderSize(property)); netPacket.Property = property; return netPacket; } internal NetPacket PoolGetPacket(int size) { if (size > NetConstants.MaxPacketSize) { return new NetPacket(size); } NetPacket poolHead; lock (_poolLock) { poolHead = _poolHead; if (poolHead == null) { return new NetPacket(size); } _poolHead = _poolHead.Next; _poolCount--; } poolHead.Size = size; if (poolHead.RawData.Length < size) { poolHead.RawData = new byte[size]; } return poolHead; } internal void PoolRecycle(NetPacket packet) { if (packet.RawData.Length > NetConstants.MaxPacketSize || _poolCount >= PacketPoolSize) { return; } packet.RawData[0] = 0; lock (_poolLock) { packet.Next = _poolHead; _poolHead = packet; _poolCount++; } } static NetManager() { Primes = new int[72] { 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 }; MulticastAddressV6 = IPAddress.Parse("ff02::1"); IPv6Support = Socket.OSSupportsIPv6; } private bool ProcessError(SocketException ex) { switch (ex.SocketErrorCode) { case SocketError.NotConnected: NotConnected = true; return true; case SocketError.OperationAborted: case SocketError.Interrupted: case SocketError.NotSocket: return true; default: NetDebug.WriteError($"[R]Error code: {ex.SocketErrorCode} - {ex}"); CreateEvent(NetEvent.EType.Error, null, null, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); break; case SocketError.WouldBlock: case SocketError.MessageSize: case SocketError.NetworkReset: case SocketError.ConnectionReset: case SocketError.TimedOut: break; } return false; } private void ManualReceive(Socket socket, EndPoint bufferEndPoint, int maxReceive) { try { int num = 0; while (socket.Available > 0) { ReceiveFrom(socket, ref bufferEndPoint); num++; if (num == maxReceive) { break; } } } catch (SocketException ex) { ProcessError(ex); } catch (ObjectDisposedException) { } catch (Exception ex3) { NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex3); } } private void NativeReceiveLogic() { IntPtr handle = _udpSocketv4.Handle; IntPtr s2 = _udpSocketv6?.Handle ?? IntPtr.Zero; byte[] address2 = new byte[16]; byte[] address3 = new byte[28]; IPEndPoint tempEndPoint = new IPEndPoint(IPAddress.Any, 0); List<Socket> list = new List<Socket>(2); Socket udpSocketv = _udpSocketv4; Socket udpSocketv2 = _udpSocketv6; NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize); while (IsRunning) { try { if (udpSocketv2 == null) { if (!NativeReceiveFrom(handle, address2)) { break; } continue; } bool flag = false; if (udpSocketv.Available != 0 || list.Contains(udpSocketv)) { if (!NativeReceiveFrom(handle, address2)) { break; } flag = true; } if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2)) { if (!NativeReceiveFrom(s2, address3)) { break; } flag = true; } list.Clear(); if (!flag) { list.Add(udpSocketv); list.Add(udpSocketv2); Socket.Select(list, null, null, 500000); } } catch (SocketException ex) { if (ProcessError(ex)) { break; } } catch (ObjectDisposedException) { break; } catch (ThreadAbortException) { break; } catch (Exception ex4) { NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4); } } bool NativeReceiveFrom(IntPtr s, byte[] address) { int socketAddressSize = address.Length; packet.Size = NativeSocket.RecvFrom(s, packet.RawData, NetConstants.MaxPacketSize, address, ref socketAddressSize); if (packet.Size == 0) { return true; } if (packet.Size == -1) { return !ProcessError(new SocketException((int)NativeSocket.GetSocketError())); } short num = (short)((address[1] << 8) | address[0]); tempEndPoint.Port = (ushort)((address[2] << 8) | address[3]); if ((NativeSocket.UnixMode && num == 10) || (!NativeSocket.UnixMode && num == 23)) { uint num2 = (uint)((address[27] << 24) + (address[26] << 16) + (address[25] << 8) + address[24]); tempEndPoint.Address = new IPAddress(new ReadOnlySpan<byte>(address, 8, 16), num2); } else { long newAddress = (uint)((address[4] & 0xFF) | ((address[5] << 8) & 0xFF00) | ((address[6] << 16) & 0xFF0000) | (address[7] << 24)); tempEndPoint.Address = new IPAddress(newAddress); } if (TryGetPeer(tempEndPoint, out var actualValue)) { OnMessageReceived(packet, actualValue); } else { OnMessageReceived(packet, tempEndPoint); tempEndPoint = new IPEndPoint(IPAddress.Any, 0); } packet = PoolGetPacket(NetConstants.MaxPacketSize); return true; } } private void ReceiveFrom(Socket s, ref EndPoint bufferEndPoint) { NetPacket netPacket = PoolGetPacket(NetConstants.MaxPacketSize); netPacket.Size = s.ReceiveFrom(netPacket.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None, ref bufferEndPoint); OnMessageReceived(netPacket, (IPEndPoint)bufferEndPoint); } private void ReceiveLogic() { EndPoint bufferEndPoint = new IPEndPoint(IPAddress.Any, 0); EndPoint bufferEndPoint2 = new IPEndPoint(IPAddress.IPv6Any, 0); List<Socket> list = new List<Socket>(2); Socket udpSocketv = _udpSocketv4; Socket udpSocketv2 = _udpSocketv6; while (IsRunning) { try { if (udpSocketv2 == null) { if (udpSocketv.Available != 0 || udpSocketv.Poll(500000, SelectMode.SelectRead)) { ReceiveFrom(udpSocketv, ref bufferEndPoint); } continue; } bool flag = false; if (udpSocketv.Available != 0 || list.Contains(udpSocketv)) { ReceiveFrom(udpSocketv, ref bufferEndPoint); flag = true; } if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2)) { ReceiveFrom(udpSocketv2, ref bufferEndPoint2); flag = true; } list.Clear(); if (!flag) { list.Add(udpSocketv); list.Add(udpSocketv2); Socket.Select(list, null, null, 500000); } } catch (SocketException ex) { if (ProcessError(ex)) { break; } } catch (ObjectDisposedException) { break; } catch (ThreadAbortException) { break; } catch (Exception ex4) { NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4); } } } public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool manualMode) { if (IsRunning && !NotConnected) { return false; } NotConnected = false; _manualMode = manualMode; UseNativeSockets = UseNativeSockets && NativeSocket.IsSupported; _udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); if (!BindSocket(_udpSocketv4, new IPEndPoint(addressIPv4, port))) { return false; } LocalPort = ((IPEndPoint)_udpSocketv4.LocalEndPoint).Port; IsRunning = true; if (_manualMode) { _bufferEndPointv4 = new IPEndPoint(IPAddress.Any, 0); } if (IPv6Support && IPv6Enabled) { _udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort))) { if (_manualMode) { _bufferEndPointv6 = new IPEndPoint(IPAddress.IPv6Any, 0); } } else { _udpSocketv6 = null; } } if (!manualMode) { ThreadStart start = ReceiveLogic; if (UseNativeSockets) { start = NativeReceiveLogic; } _receiveThread = new Thread(start) { Name = $"ReceiveThread({LocalPort})", IsBackground = true }; _receiveThread.Start(); if (_logicThread == null) { _logicThread = new Thread(UpdateLogic) { Name = "LogicThread", IsBackground = true }; _logicThread.Start(); } } return true; } private bool BindSocket(Socket socket, IPEndPoint ep) { socket.ReceiveTimeout = 500; socket.SendTimeout = 500; socket.ReceiveBufferSize = 1048576; socket.SendBufferSize = 1048576; socket.Blocking = true; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { try { socket.IOControl(-1744830452, new byte[1], null); } catch { } } try { socket.ExclusiveAddressUse = !ReuseAddress; socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, ReuseAddress); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, DontRoute); } catch { } if (ep.AddressFamily == AddressFamily.InterNetwork) { Ttl = 255; try { socket.EnableBroadcast = true; } catch (SocketException ex) { NetDebug.WriteError($"[B]Broadcast error: {ex.SocketErrorCode}"); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { try { socket.DontFragment = true; } catch (SocketException ex2) { NetDebug.WriteError($"[B]DontFragment error: {ex2.SocketErrorCode}"); } } } try { socket.Bind(ep); if (ep.AddressFamily == AddressFamily.InterNetworkV6) { try { socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(MulticastAddressV6)); } catch (Exception) { } } } catch (SocketException ex4) { switch (ex4.SocketErrorCode) { case SocketError.AddressAlreadyInUse: if (socket.AddressFamily == AddressFamily.InterNetworkV6) { try { socket.DualMode = false; socket.Bind(ep); } catch (SocketException ex5) { NetDebug.WriteError($"[B]Bind exception: {ex5}, errorCode: {ex5.SocketErrorCode}"); return false; } return true; } break; case SocketError.AddressFamilyNotSupported: return true; } NetDebug.WriteError($"[B]Bind exception: {ex4}, errorCode: {ex4.SocketErrorCode}"); return false; } return true; } internal int SendRawAndRecycle(NetPacket packet, IPEndPoint remoteEndPoint) { int result = SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint); PoolRecycle(packet); return result; } internal int SendRaw(NetPacket packet, IPEndPoint remoteEndPoint) { return SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint); } internal unsafe int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEndPoint) { if (!IsRunning) { return 0; } NetPacket netPacket = null; if (_extraPacketLayer != null) { netPacket = PoolGetPacket(length + _extraPacketLayer.ExtraPacketSizeForLayer); Buffer.BlockCopy(message, start, netPacket.RawData, 0, length); start = 0; _extraPacketLayer.ProcessOutBoundPacket(ref remoteEndPoint, ref netPacket.RawData, ref start, ref length); message = netPacket.RawData; } Socket socket = _udpSocketv4; if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support) { socket = _udpSocketv6; if (socket == null) { return 0; } } int num; try { if (UseNativeSockets && remoteEndPoint is NetPeer netPeer) { fixed (byte* pinnedBuffer = &message[start]) { num = NativeSocket.SendTo(socket.Handle, pinnedBuffer, length, netPeer.NativeAddress, netPeer.NativeAddress.Length); } if (num == -1) { throw NativeSocket.GetSocketException(); } } else { num = socket.SendTo(message, start, length, SocketFlags.None, remoteEndPoint); } } catch (SocketException ex) { switch (ex.SocketErrorCode) { case SocketError.Interrupted: case SocketError.NoBufferSpaceAvailable: return 0; case SocketError.MessageSize: return 0; case SocketError.NetworkUnreachable: case SocketError.HostUnreachable: if (DisconnectOnUnreachable && remoteEndPoint is NetPeer peer) { DisconnectPeerForce(peer, (ex.SocketErrorCode == SocketError.HostUnreachable) ? DisconnectReason.HostUnreachable : DisconnectReason.NetworkUnreachable, ex.SocketErrorCode, null); } CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); return -1; case SocketError.Shutdown: CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); return -1; default: NetDebug.WriteError($"[S] {ex}"); return -1; } } catch (Exception value) { NetDebug.WriteError($"[S] {value}"); return 0; } finally { if (netPacket != null) { PoolRecycle(netPacket); } } if (num <= 0) { return 0; } if (EnableStatistics) { Statistics.IncrementPacketsSent(); Statistics.AddBytesSent(length); } return num; } public bool SendBroadcast(NetDataWriter writer, int port) { return SendBroadcast(writer.Data, 0, writer.Length, port); } public bool SendBroadcast(byte[] data, int port) { return SendBroadcast(data, 0, data.Length, port); } public bool SendBroadcast(byte[] data, int start, int length, int port) { if (!IsRunning) { return false; } NetPacket netPacket; if (_extraPacketLayer != null) { int headerSize = NetPacket.GetHeaderSize(PacketProperty.Broadcast); netPacket = PoolGetPacket(headerSize + length + _extraPacketLayer.ExtraPacketSizeForLayer); netPacket.Property = PacketProperty.Broadcast; Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length); int offset = 0; int length2 = length + headerSize; IPEndPoint endPoint = null; _extraPacketLayer.ProcessOutBoundPacket(ref endPoint, ref netPacket.RawData, ref offset, ref length2); } else { netPacket = PoolGetWithData(PacketProperty.Broadcast, data, start, length); } bool flag = false; bool flag2 = false; try { flag = _udpSocketv4.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port)) > 0; if (_udpSocketv6 != null) { flag2 = _udpSocketv6.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(MulticastAddressV6, port)) > 0; } } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.HostUnreachable) { return flag; } NetDebug.WriteError($"[S][MCAST] {ex}"); return flag; } catch (Exception value) { NetDebug.WriteError($"[S][MCAST] {value}"); return flag; } finally { PoolRecycle(netPacket); } return flag || flag2; } private void CloseSocket() { IsRunning = false; _udpSocketv4?.Close(); _udpSocketv6?.Close(); _udpSocketv4 = null; _udpSocketv6 = null; if (_receiveThread != null && _receiveThread != Thread.CurrentThread) { _receiveThread.Join(); } _receiveThread = null; } } internal enum PacketProperty : byte { Unreliable, Channeled, Ack, Ping, Pong, ConnectRequest, ConnectAccept, Disconnect, UnconnectedMessage, MtuCheck, MtuOk, Broadcast, Merged, ShutdownOk, PeerNotFound, InvalidProtocol, NatMessage, Empty } internal sealed class NetPacket { private static readonly int PropertiesCount; private static readonly int[] HeaderSizes; public byte[] RawData; public int Size; public object UserData; public NetPacket Next; public PacketProperty Property { get { return (PacketProperty)(RawData[0] & 0x1Fu); } set { RawData[0] = (byte)((RawData[0] & 0xE0u) | (uint)value); } } public byte ConnectionNumber { get { return (byte)((RawData[0] & 0x60) >> 5); } set { RawData[0] = (byte)((RawData[0] & 0x9Fu) | (uint)(value << 5)); } } public ushort Sequence { get { return BitConverter.ToUInt16(RawData, 1); } set { FastBitConverter.GetBytes(RawData, 1, value); } } public bool IsFragmented => (RawData[0] & 0x80) != 0; public byte ChannelId { get { return RawData[3]; } set { RawData[3] = value; } } public ushort FragmentId { get { return BitConverter.ToUInt16(RawData, 4); } set { FastBitConverter.GetBytes(RawData, 4, value); } } public ushort FragmentPart { get { return BitConverter.ToUInt16(RawData, 6); } set { FastBitConverter.GetBytes(RawData, 6, value); } } public ushort FragmentsTotal { get { return BitConverter.ToUInt16(RawData, 8); } set { FastBitConverter.GetBytes(RawData, 8, value); } } static NetPacket() { PropertiesCount = Enum.GetValues(typeof(PacketProperty)).Length; HeaderSizes = NetUtils.AllocatePinnedUninitializedArray<int>(PropertiesCount); for (int i = 0; i < HeaderSizes.Length; i++) { switch ((PacketProperty)(byte)i) { case PacketProperty.Channeled: case PacketProperty.Ack: HeaderSizes[i] = 4; break; case PacketProperty.Ping: HeaderSizes[i] = 3; break; case PacketProperty.ConnectRequest: HeaderSizes[i] = 18; break; case PacketProperty.ConnectAccept: HeaderSizes[i] = 15; break; case PacketProperty.Disconnect: HeaderSizes[i] = 9; break; case PacketProperty.Pong: HeaderSizes[i] = 11; break; default: HeaderSizes[i] = 1; break; } } } public void MarkFragmented() { RawData[0] |= 128; } public NetPacket(int size) { RawData = new byte[size]; Size = size; } public NetPacket(PacketProperty property, int size) { size += GetHeaderSize(property); RawData = new byte[size]; Property = property; Size = size; } public static int GetHeaderSize(PacketProperty property) { return HeaderSizes[(uint)property]; } public int GetHeaderSize() { return HeaderSizes[RawData[0] & 0x1F]; } public bool Verify() { byte b = (byte)(RawData[0] & 0x1Fu); if (b >= PropertiesCount) { return false; } int num = HeaderSizes[b]; bool flag = (RawData[0] & 0x80) != 0; if (Size >= num) { if (flag) { return Size >= num + 6; } return true; } return false; } public static implicit operator Span<byte>(NetPacket p) { return new Span<byte>(p.RawData, 0, p.Size); } } [Flags] public enum ConnectionState : byte { Outgoing = 2, Connected = 4, ShutdownRequested = 8, Disconnected = 0x10, EndPointChange = 0x20, Any = 0x2E } internal enum ConnectRequestResult { None, P2PLose, Reconnection, NewConnection } internal enum DisconnectResult { None, Reject, Disconnect } internal enum ShutdownResult { None, Success, WasConnected } public class NetPeer : IPEndPoint { private class IncomingFragments { public NetPacket[] Fragments; public int ReceivedCount; public int TotalSize; public byte ChannelId; } private int _rtt; private int _avgRtt; private int _rttCount; private double _resendDelay = 27.0; private float _pingSendTimer; private float _rttResetTimer; private readonly Stopwatch _pingTimer = new Stopwatch(); private volatile float _timeSinceLastPacket; private long _remoteDelta; private readonly object _shutdownLock = new object(); internal volatile NetPeer NextPeer; internal NetPeer PrevPeer; private NetPacket[] _unreliableSecondQueue; private NetPacket[] _unreliableChannel; private int _unreliablePendingCount; private readonly object _unreliableChannelLock = new object(); private readonly ConcurrentQueue<BaseChannel> _channelSendQueue; private readonly BaseChannel[] _channels; private int _mtu; private int _mtuIdx; private bool _finishMtu; private float _mtuCheckTimer; private int _mtuCheckAttempts; private const int MtuCheckDelay = 1000; private const int MaxMtuCheckAttempts = 4; private readonly object _mtuMutex = new object(); private int _fragmentId; private readonly Dictionary<ushort, IncomingFragments> _holdedFragments; private readonly Dictionary<ushort, ushort> _deliveredFragments; private readonly NetPacket _mergeData; private int _mergePos; private int _mergeCount; private int _connectAttempts; private float _connectTimer; private long _connectTime; private byte _connectNum; private ConnectionState _connectionState; private NetPacket _shutdownPacket; private const int ShutdownDelay = 300; private float _shutdownTimer; private readonly NetPacket _pingPacket; private readonly NetPacket _pongPacket; private readonly NetPacket _connectRequestPacket; private readonly NetPacket _connectAcceptPacket; public readonly NetManager NetManager; public readonly int Id; public object Tag; public readonly NetStatistics Statistics; private SocketAddress _cachedSocketAddr; private int _cachedHashCode; internal byte[] NativeAddress; internal byte ConnectionNum { get { return _connectNum; } private set { _connectNum = value; _mergeData.ConnectionNumber = value; _pingPacket.ConnectionNumber = value; _pongPacket.ConnectionNumber = value; } } public ConnectionState ConnectionState => _connectionState; internal long ConnectTime => _connectTime; public int RemoteId { get; private set; } public int Ping => _avgRtt / 2; public int RoundTripTime => _avgRtt; public int Mtu => _mtu; public long RemoteTimeDelta => _remoteDelta; public DateTime RemoteUtcTime => new DateTime(DateTime.UtcNow.Ticks + _remoteDelta); public float TimeSinceLastPacket => _timeSinceLastPacket; internal double ResendDelay => _resendDelay; public override SocketAddress Serialize() { return _cachedSocketAddr; } public override int GetHashCode() { return _cachedHashCode; } internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) : base(remoteEndPoint.Address, remoteEndPoint.Port) { Id = id; Statistics = new NetStatistics(); NetManager = netManager; _cachedSocketAddr = base.Serialize(); if (NetManager.UseNativeSockets) { NativeAddress = new byte[_cachedSocketAddr.Size]; for (int i = 0; i < _cachedSocketAddr.Size; i++) { NativeAddress[i] = _cachedSocketAddr[i]; } } _cachedHashCode = base.GetHashCode(); ResetMtu(); _connectionState = ConnectionState.Connected; _mergeData = new NetPacket(PacketProperty.Merged, NetConstants.MaxPacketSize); _pongPacket = new NetPacket(PacketProperty.Pong, 0); _pingPacket = new NetPacket(PacketProperty.Ping, 0) { Sequence = 1 }; _unreliableSecondQueue = new NetPacket[8]; _unreliableChannel = new NetPacket[8]; _holdedFragments = new Dictionary<ushort, IncomingFragments>(); _deliveredFragments = new Dictionary<ushort, ushort>(); _channels = new BaseChannel[netManager.ChannelsCount * 4]; _channelSendQueue = new ConcurrentQueue<BaseChannel>(); } internal void InitiateEndPointChange() { ResetMtu(); _connectionState = ConnectionState.EndPointChange; } internal void FinishEndPointChange(IPEndPoint newEndPoint) { if (_connectionState != ConnectionState.EndPointChange) { return; } _connectionState = ConnectionState.Connected; base.Address = newEndPoint.Address; base.Port = newEndPoint.Port; if (NetManager.UseNativeSockets) { NativeAddress = new byte[_cachedSocketAddr.Size]; for (int i = 0; i < _cachedSocketAddr.Size; i++) { NativeAddress[i] = _cachedSocketAddr[i]; } } _cachedSocketAddr = base.Serialize(); _cachedHashCode = base.GetHashCode(); } internal void ResetMtu() { _finishMtu = !NetManager.MtuDiscovery; if (NetManager.MtuOverride > 0) { OverrideMtu(NetManager.MtuOverride); } else { SetMtu(0); } } private void SetMtu(int mtuIdx) { _mtuIdx = mtuIdx; _mtu = NetConstants.PossibleMtu[mtuIdx] - NetManager.ExtraPacketSizeForLayer; } private void OverrideMtu(int mtuValue) { _mtu = mtuValue; _finishMtu = true; } public int GetPacketsCountInReliableQueue(byte channelNumber, bool ordered) { int num = channelNumber * 4 + (ordered ? 2 : 0); BaseChannel baseChannel = _channels[num]; if (baseChannel == null) { return 0; } return ((ReliableChannel)baseChannel).PacketsInQueue; } public PooledPacket CreatePacketFromPool(DeliveryMethod deliveryMethod, byte channelNumber) { int mtu = _mtu; NetPacket netPacket = NetManager.PoolGetPacket(mtu); if (deliveryMethod == DeliveryMethod.Unreliable) { netPacket.Property = PacketProperty.Unreliable; return new PooledPacket(netPacket, mtu, 0); } netPacket.Property = PacketProperty.Channeled; return new PooledPacket(netPacket, mtu, (byte)((uint)(channelNumber * 4) + (ui