Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BM Suits v1.0.2
BM _Suits.dll
Decompiled 7 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BM _Suits")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BM _Suits")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("6b42616d-1a9e-46f4-a488-7cc9797b51fb")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] internal static class AdvancedSuitMaterials { [Serializable] private sealed class AdvancedJson { public AdvancedLayer[] Layers; } [Serializable] private sealed class AdvancedLayer { public string Name; public string Mask; public string Material; public float Threshold = 0.5f; public float Opacity = 1f; public float EmissiveIntensity = 1f; public string EmissiveColor = "1,1,1,1"; } private sealed class AdvancedSuitDefinition { public string SuitName; public string SuitDirectory; public string JsonPath; public string BaseTexturePath; public AdvancedLayer[] Layers; } private sealed class LoadedLayer { public AdvancedLayer Definition; public Texture2D Mask; public Material Material; } private sealed class RendererState { public SkinnedMeshRenderer Renderer; public Mesh OriginalMesh; public Material[] OriginalMaterials; public Mesh GeneratedMesh; public Material[] GeneratedMaterials; } [HarmonyPatch(typeof(StartOfRound), "Start")] private static class StartOfRoundPatch { [HarmonyPostfix] private static void Postfix(StartOfRound __instance) { if (!((Object)(object)__instance == (Object)null)) { ((MonoBehaviour)__instance).StartCoroutine(InitializeAfterMoreSuits(__instance)); } } } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] private static class DisconnectPatch { [HarmonyPostfix] private static void Postfix() { RestoreAllRenderers(); } } private static bool initialized; private static readonly Dictionary<string, AdvancedSuitDefinition> definitions = new Dictionary<string, AdvancedSuitDefinition>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<int, RendererState> rendererStates = new Dictionary<int, RendererState>(); private static readonly List<string> temporaryCompatibilityFiles = new List<string>(); private static ManualLogSource Logger => Plugin.Log; internal static void Initialize() { if (!initialized) { initialized = true; ScanAdvancedSuits(); PrepareMoreSuitsCompatibilityFiles(); Logger.LogInfo((object)("Advanced suit material system initialized. Found " + definitions.Count + " advanced suit definition(s).")); } } private static void ScanAdvancedSuits() { definitions.Clear(); string moreSuitsDirectory = Plugin.MoreSuitsDirectory; if (!Directory.Exists(moreSuitsDirectory)) { Logger.LogDebug((object)("MoreSuits directory not found: " + moreSuitsDirectory)); return; } string[] directories = Directory.GetDirectories(moreSuitsDirectory, "*", SearchOption.TopDirectoryOnly); string[] array = directories; foreach (string text in array) { string fileName = Path.GetFileName(text); if (string.IsNullOrWhiteSpace(fileName)) { continue; } string text2 = FindCaseInsensitiveFile(text, fileName + ".png"); if (string.IsNullOrEmpty(text2)) { continue; } string text3 = FindAdvancedDirectory(text); if (string.IsNullOrEmpty(text3)) { continue; } string text4 = FindCaseInsensitiveFile(text3, fileName + ".json"); if (!string.IsNullOrEmpty(text4)) { AdvancedJson advancedJson = ReadJson(text4); if (advancedJson != null) { AdvancedSuitDefinition advancedSuitDefinition = new AdvancedSuitDefinition(); advancedSuitDefinition.SuitName = fileName; advancedSuitDefinition.SuitDirectory = text; advancedSuitDefinition.JsonPath = text4; advancedSuitDefinition.BaseTexturePath = text2; advancedSuitDefinition.Layers = advancedJson.Layers ?? new AdvancedLayer[0]; definitions[fileName] = advancedSuitDefinition; Logger.LogInfo((object)("Advanced suit found: " + fileName)); } } } } private static AdvancedJson ReadJson(string path) { try { string text = File.ReadAllText(path); return JsonUtility.FromJson<AdvancedJson>(text); } catch (Exception ex) { Logger.LogError((object)("Failed reading advanced JSON '" + path + "': " + ex.Message)); return null; } } private static void PrepareMoreSuitsCompatibilityFiles() { temporaryCompatibilityFiles.Clear(); foreach (AdvancedSuitDefinition value in definitions.Values) { if (string.IsNullOrEmpty(value.BaseTexturePath)) { continue; } string text = Path.Combine(Plugin.MoreSuitsDirectory, value.SuitName + ".png"); try { File.Copy(value.BaseTexturePath, text, overwrite: true); if (!temporaryCompatibilityFiles.Contains<string>(text, StringComparer.OrdinalIgnoreCase)) { temporaryCompatibilityFiles.Add(text); } Logger.LogDebug((object)("Prepared MoreSuits compatibility texture: " + text)); } catch (Exception ex) { Logger.LogError((object)("Failed preparing MoreSuits compatibility texture for " + value.SuitName + ": " + ex.Message)); } } } private static void RemoveTemporaryCompatibilityFiles() { foreach (string temporaryCompatibilityFile in temporaryCompatibilityFiles) { try { if (File.Exists(temporaryCompatibilityFile)) { File.Delete(temporaryCompatibilityFile); Logger.LogDebug((object)("Removed temporary MoreSuits compatibility texture: " + temporaryCompatibilityFile)); } } catch (Exception ex) { Logger.LogWarning((object)("Could not remove temporary MoreSuits compatibility texture '" + temporaryCompatibilityFile + "': " + ex.Message)); } } temporaryCompatibilityFiles.Clear(); } private static IEnumerator InitializeAfterMoreSuits(StartOfRound round) { yield return null; yield return null; ApplyRegisteredSuitMaterials(round); RemoveTemporaryCompatibilityFiles(); yield return null; if (round.allPlayerScripts == null) { yield break; } PlayerControllerB[] allPlayerScripts = round.allPlayerScripts; foreach (PlayerControllerB player in allPlayerScripts) { if (!((Object)(object)player == (Object)null)) { ApplyToPlayer(player); } } } private static void ApplyRegisteredSuitMaterials(StartOfRound round) { if ((Object)(object)round.unlockablesList == (Object)null || round.unlockablesList.unlockables == null) { return; } foreach (KeyValuePair<string, AdvancedSuitDefinition> definition in definitions) { UnlockableItem val = FindSuit(round, definition.Key); if (val == null) { Logger.LogWarning((object)("Could not find registered MoreSuits suit: " + definition.Key)); continue; } if ((Object)(object)val.suitMaterial == (Object)null) { Logger.LogWarning((object)("Suit material is null for: " + definition.Key)); continue; } ApplyBaseMaterialLayers(val.suitMaterial, definition.Value); Logger.LogInfo((object)("Applied advanced suit definition: " + definition.Key)); } } private static UnlockableItem FindSuit(StartOfRound round, string suitName) { foreach (UnlockableItem unlockable in round.unlockablesList.unlockables) { if (unlockable != null) { string a = NormalizeSuitName(unlockable.unlockableName); if (string.Equals(a, suitName, StringComparison.OrdinalIgnoreCase)) { return unlockable; } } } return null; } private static void ApplyBaseMaterialLayers(Material material, AdvancedSuitDefinition definition) { if ((Object)(object)material == (Object)null || definition == null || definition.Layers == null) { return; } AdvancedLayer[] layers = definition.Layers; foreach (AdvancedLayer advancedLayer in layers) { if (advancedLayer != null && advancedLayer.Name.Equals("Emissive", StringComparison.OrdinalIgnoreCase)) { ApplyEmissiveLayer(material, definition, advancedLayer); } } } private static void ApplyEmissiveLayer(Material material, AdvancedSuitDefinition definition, AdvancedLayer layer) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(layer.Mask)) { return; } string text = FindAdvancedAsset(definition, layer.Mask); if (!File.Exists(text)) { Logger.LogWarning((object)("Emissive mask not found: " + text)); return; } Texture2D val = LoadTexture(text); if (!((Object)(object)val == (Object)null)) { if (material.HasProperty("_EmissiveColorMap")) { material.SetTexture("_EmissiveColorMap", (Texture)(object)val); } if (material.HasProperty("_UseEmissiveIntensity")) { material.SetFloat("_UseEmissiveIntensity", 1f); } if (material.HasProperty("_EmissiveIntensity")) { material.SetFloat("_EmissiveIntensity", layer.EmissiveIntensity); } if (material.HasProperty("_EmissiveColor")) { material.SetColor("_EmissiveColor", ParseColor(layer.EmissiveColor)); } material.EnableKeyword("_EMISSIVE_COLOR_MAP"); Logger.LogInfo((object)("Applied emissive layer to " + definition.SuitName + ": " + layer.Mask)); } } private static void ApplyToPlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return; } RestorePlayerRenderers(player); UnlockableItem currentSuit = GetCurrentSuit(player); if (currentSuit == null) { return; } string key = NormalizeSuitName(currentSuit.unlockableName); if (!definitions.TryGetValue(key, out var value)) { return; } SkinnedMeshRenderer[] array = (SkinnedMeshRenderer[])(object)new SkinnedMeshRenderer[3] { player.thisPlayerModel, player.thisPlayerModelLOD1, player.thisPlayerModelLOD2 }; SkinnedMeshRenderer[] array2 = array; foreach (SkinnedMeshRenderer val in array2) { if (!((Object)(object)val == (Object)null)) { ApplyDefinitionToRenderer(val, value); } } } private static UnlockableItem GetCurrentSuit(PlayerControllerB player) { if ((Object)(object)player == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.unlockablesList == (Object)null || StartOfRound.Instance.unlockablesList.unlockables == null) { return null; } int currentSuitID = player.currentSuitID; List<UnlockableItem> unlockables = StartOfRound.Instance.unlockablesList.unlockables; if (currentSuitID < 0 || currentSuitID >= unlockables.Count) { return null; } return unlockables[currentSuitID]; } private static void ApplyDefinitionToRenderer(SkinnedMeshRenderer renderer, AdvancedSuitDefinition definition) { if ((Object)(object)renderer == (Object)null || (Object)(object)renderer.sharedMesh == (Object)null || definition == null) { return; } Mesh sharedMesh = renderer.sharedMesh; Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMesh.subMeshCount == 0 || sharedMesh.uv == null || sharedMesh.uv.Length == 0) { Logger.LogWarning((object)("Renderer has no usable UV data: " + ((Object)renderer).name)); return; } List<LoadedLayer> list = LoadMaterialLayers(definition); if (list.Count == 0) { return; } RendererState rendererState = new RendererState(); rendererState.Renderer = renderer; rendererState.OriginalMesh = sharedMesh; rendererState.OriginalMaterials = sharedMaterials; rendererStates[((Object)renderer).GetInstanceID()] = rendererState; Mesh val = Object.Instantiate<Mesh>(sharedMesh); ((Object)val).name = ((Object)sharedMesh).name + "_BM_Suits_Layered_" + definition.SuitName; int subMeshCount = sharedMesh.subMeshCount; int count = list.Count; val.subMeshCount = subMeshCount + count; Material[] array = (Material[])(object)new Material[subMeshCount + count]; for (int i = 0; i < subMeshCount; i++) { if (sharedMaterials != null && i < sharedMaterials.Length) { array[i] = sharedMaterials[i]; } } for (int j = 0; j < count; j++) { array[subMeshCount + j] = list[j].Material; } Vector2[] uv = sharedMesh.uv; int[] array2 = BuildTriangleLayerAssignments(sharedMesh, uv, list); int[] array3 = new int[count]; List<int>[] array4 = new List<int>[subMeshCount]; for (int k = 0; k < subMeshCount; k++) { array4[k] = new List<int>(); } List<int>[] array5 = new List<int>[count]; for (int l = 0; l < count; l++) { array5[l] = new List<int>(); } int num = 0; for (int m = 0; m < subMeshCount; m++) { int[] triangles = sharedMesh.GetTriangles(m); for (int n = 0; n + 2 < triangles.Length; n += 3) { int num2 = num; int num3 = -1; if (num2 >= 0 && num2 < array2.Length) { num3 = array2[num2]; } if (num3 >= 0 && num3 < count) { array5[num3].Add(triangles[n]); array5[num3].Add(triangles[n + 1]); array5[num3].Add(triangles[n + 2]); array3[num3]++; } else { array4[m].Add(triangles[n]); array4[m].Add(triangles[n + 1]); array4[m].Add(triangles[n + 2]); } num++; } } for (int num4 = 0; num4 < subMeshCount; num4++) { val.SetTriangles(array4[num4], num4, false); } for (int num5 = 0; num5 < count; num5++) { val.SetTriangles(array5[num5], subMeshCount + num5, false); } val.RecalculateBounds(); renderer.sharedMesh = val; ((Renderer)renderer).sharedMaterials = array; rendererState.GeneratedMesh = val; rendererState.GeneratedMaterials = array; int num6 = 0; for (int num7 = 0; num7 < array3.Length; num7++) { num6 += array3[num7]; } Logger.LogInfo((object)("Built layered renderer for " + definition.SuitName + " / " + ((Object)renderer).name + ": " + num6 + " triangle(s) assigned to advanced layers.")); for (int num8 = 0; num8 < list.Count; num8++) { Logger.LogInfo((object)(" Layer " + list[num8].Definition.Name + ": " + array3[num8] + " triangle(s)")); } } private static int[] BuildTriangleLayerAssignments(Mesh mesh, Vector2[] uv, List<LoadedLayer> layers) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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) int num = 0; for (int i = 0; i < mesh.subMeshCount; i++) { num += (int)(mesh.GetIndexCount(i) / 3); } int[] array = new int[num]; for (int j = 0; j < array.Length; j++) { array[j] = -1; } int num2 = 0; for (int k = 0; k < mesh.subMeshCount; k++) { int[] triangles = mesh.GetTriangles(k); for (int l = 0; l + 2 < triangles.Length; l += 3) { int num3 = triangles[l]; int num4 = triangles[l + 1]; int num5 = triangles[l + 2]; if (num3 < 0 || num3 >= uv.Length || num4 < 0 || num4 >= uv.Length || num5 < 0 || num5 >= uv.Length) { num2++; continue; } Vector2 uv2 = uv[num3]; Vector2 uv3 = uv[num4]; Vector2 uv4 = uv[num5]; for (int m = 0; m < layers.Count; m++) { LoadedLayer loadedLayer = layers[m]; if (!((Object)(object)loadedLayer.Mask == (Object)null) && TriangleMatchesMask(loadedLayer.Mask, uv2, uv3, uv4, loadedLayer.Definition.Threshold)) { array[num2] = m; break; } } num2++; } } return array; } private static bool TriangleMatchesMask(Texture2D mask, Vector2 uv0, Vector2 uv1, Vector2 uv2, float threshold) { //IL_0009: 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) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0021: 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_0028: 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_0034: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //IL_004e: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) Vector2[] array = (Vector2[])(object)new Vector2[7] { uv0, uv1, uv2, Vector2.Lerp(uv0, uv1, 0.5f), Vector2.Lerp(uv1, uv2, 0.5f), Vector2.Lerp(uv2, uv0, 0.5f), (uv0 + uv1 + uv2) / 3f }; int num = 0; for (int i = 0; i < array.Length; i++) { float num2 = SampleMask(mask, array[i]); if (num2 >= threshold) { num++; } } return num >= 4; } private static float SampleMask(Texture2D texture, Vector2 uv) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0022: 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_002e: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(uv.x); float num2 = Mathf.Clamp01(uv.y); Color pixelBilinear = texture.GetPixelBilinear(num, num2); return Mathf.Max(pixelBilinear.r, Mathf.Max(pixelBilinear.g, pixelBilinear.b)); } private static List<LoadedLayer> LoadMaterialLayers(AdvancedSuitDefinition definition) { List<LoadedLayer> list = new List<LoadedLayer>(); if (definition == null || definition.Layers == null) { return list; } AdvancedLayer[] layers = definition.Layers; foreach (AdvancedLayer advancedLayer in layers) { if (advancedLayer == null || string.IsNullOrWhiteSpace(advancedLayer.Name) || advancedLayer.Name.Equals("Emissive", StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(advancedLayer.Mask)) { continue; } string text = advancedLayer.Material; if (string.IsNullOrWhiteSpace(text)) { if (advancedLayer.Name.Equals("Glass", StringComparison.OrdinalIgnoreCase)) { text = "MoreMaterials-Glass"; } else { if (!advancedLayer.Name.Equals("Transparent", StringComparison.OrdinalIgnoreCase)) { Logger.LogWarning((object)("Layer '" + advancedLayer.Name + "' has no Material specified.")); continue; } text = "MoreMaterials-Transparent"; } } Material val = FindMoreMaterialsMaterial(text); if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)("Could not find MoreMaterials material '" + text + "' for " + definition.SuitName)); continue; } string text2 = FindAdvancedAsset(definition, advancedLayer.Mask); if (!File.Exists(text2)) { Logger.LogWarning((object)("Layer mask not found: " + text2)); continue; } Texture2D val2 = LoadTexture(text2); if ((Object)(object)val2 == (Object)null) { continue; } Material val3 = Object.Instantiate<Material>(val); ((Object)val3).name = "BM_Suits_" + definition.SuitName + "_" + advancedLayer.Name; Texture2D val4 = LoadTexture(definition.BaseTexturePath); if ((Object)(object)val4 != (Object)null) { if (val3.HasProperty("_BaseColorMap")) { val3.SetTexture("_BaseColorMap", (Texture)(object)val4); } if (val3.HasProperty("_BaseMap")) { val3.SetTexture("_BaseMap", (Texture)(object)val4); } val3.mainTexture = (Texture)(object)val4; } LoadedLayer loadedLayer = new LoadedLayer(); loadedLayer.Definition = advancedLayer; loadedLayer.Mask = val2; loadedLayer.Material = val3; list.Add(loadedLayer); Logger.LogInfo((object)("Loaded layer material: " + definition.SuitName + " -> " + advancedLayer.Name + " -> " + text)); } return list; } private static void RestorePlayerRenderers(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return; } SkinnedMeshRenderer[] array = (SkinnedMeshRenderer[])(object)new SkinnedMeshRenderer[3] { player.thisPlayerModel, player.thisPlayerModelLOD1, player.thisPlayerModelLOD2 }; SkinnedMeshRenderer[] array2 = array; foreach (SkinnedMeshRenderer val in array2) { if (!((Object)(object)val == (Object)null)) { RestoreRenderer(val); } } } private static void RestoreRenderer(SkinnedMeshRenderer renderer) { if ((Object)(object)renderer == (Object)null) { return; } int instanceID = ((Object)renderer).GetInstanceID(); if (!rendererStates.TryGetValue(instanceID, out var value)) { return; } if ((Object)(object)value.OriginalMesh != (Object)null) { renderer.sharedMesh = value.OriginalMesh; } if (value.OriginalMaterials != null) { ((Renderer)renderer).sharedMaterials = value.OriginalMaterials; } if ((Object)(object)value.GeneratedMesh != (Object)null) { Object.Destroy((Object)(object)value.GeneratedMesh); } if (value.GeneratedMaterials != null) { Material[] generatedMaterials = value.GeneratedMaterials; foreach (Material val in generatedMaterials) { if ((Object)(object)val == (Object)null) { continue; } bool flag = false; if (value.OriginalMaterials != null) { Material[] originalMaterials = value.OriginalMaterials; foreach (Material val2 in originalMaterials) { if ((Object)(object)val == (Object)(object)val2) { flag = true; break; } } } if (!flag) { Object.Destroy((Object)(object)val); } } } rendererStates.Remove(instanceID); } private static Material FindMoreMaterialsMaterial(string requestedName) { if (string.IsNullOrWhiteSpace(requestedName)) { return null; } Type type = FindMoreSuitsType(); if (type == null) { return null; } FieldInfo field = type.GetField("customMaterials", BindingFlags.Static | BindingFlags.Public); if (field == null) { Logger.LogWarning((object)"MoreSuits.customMaterials was not found."); return null; } object value; try { value = field.GetValue(null); } catch (Exception ex) { Logger.LogWarning((object)("Could not read MoreSuits.customMaterials: " + ex.Message)); return null; } if (!(value is IEnumerable enumerable)) { return null; } Material result = null; foreach (object item in enumerable) { Material val = (Material)((item is Material) ? item : null); if (!((Object)(object)val == (Object)null)) { if (string.Equals(((Object)val).name, requestedName, StringComparison.OrdinalIgnoreCase)) { return val; } if (((Object)val).name.StartsWith(requestedName, StringComparison.OrdinalIgnoreCase)) { result = val; } } } return result; } private static Type FindMoreSuitsType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } Type[] array2 = array; foreach (Type type in array2) { if (!(type == null) && type.GetField("customMaterials", BindingFlags.Static | BindingFlags.Public) != null) { return type; } } } return null; } private static Texture2D LoadTexture(string path) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { return null; } try { byte[] array = File.ReadAllBytes(path); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array, false)) { Object.Destroy((Object)(object)val); return null; } ((Object)val).name = "BM_Suits_" + Path.GetFileNameWithoutExtension(path); ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; val.Apply(false, false); return val; } catch (Exception ex) { Logger.LogError((object)("Failed loading texture '" + path + "': " + ex.Message)); return null; } } private static string FindAdvancedDirectory(string suitDirectory) { string[] directories = Directory.GetDirectories(suitDirectory, "*", SearchOption.TopDirectoryOnly); string[] array = directories; foreach (string text in array) { if (Path.GetFileName(text).Equals("Advanced", StringComparison.OrdinalIgnoreCase)) { return text; } } return null; } private static string FindAdvancedAsset(AdvancedSuitDefinition definition, string fileName) { if (definition == null || string.IsNullOrWhiteSpace(fileName)) { return string.Empty; } string directoryName = Path.GetDirectoryName(definition.JsonPath); return Path.Combine(directoryName, fileName); } private static string FindCaseInsensitiveFile(string directory, string expectedName) { string text = Path.Combine(directory, expectedName); if (File.Exists(text)) { return text; } if (!Directory.Exists(directory)) { return null; } string[] files = Directory.GetFiles(directory, "*", SearchOption.TopDirectoryOnly); foreach (string text2 in files) { if (Path.GetFileName(text2).Equals(expectedName, StringComparison.OrdinalIgnoreCase)) { return text2; } } return null; } private static string NormalizeSuitName(string value) { if (string.IsNullOrWhiteSpace(value)) { return value; } string text = value.Trim(); if (text.EndsWith(" suit", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - 5).TrimEnd(Array.Empty<char>()); } return text; } private static Color ParseColor(string value) { //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_0039: 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_00ea: 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) //IL_00ad: 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_00e6: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(value)) { return Color.white; } string[] array = value.Split(new char[1] { ',' }); if (array.Length < 3) { return Color.white; } float result = 1f; if (!float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(array[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result4)) { return Color.white; } if (array.Length >= 4) { float.TryParse(array[3].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result); } return new Color(result2, result3, result4, result); } private static void RestoreAllRenderers() { foreach (RendererState item in rendererStates.Values.ToList()) { if (item != null && (Object)(object)item.Renderer != (Object)null) { RestoreRenderer(item.Renderer); } } rendererStates.Clear(); RemoveTemporaryCompatibilityFiles(); } } [BepInPlugin("com.brox.BM_Suits", "BM_Suits", "1.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal const string ModGuid = "com.brox.BM_Suits"; internal const string ModName = "BM_Suits"; internal const string ModVersion = "1.5.0"; internal static ManualLogSource Log; internal static string PluginDirectory => Path.GetDirectoryName(typeof(Plugin).Assembly.Location); internal static string SoundsDirectory => Path.Combine(PluginDirectory, "sounds"); internal static string MoreSuitsDirectory => Path.Combine(PluginDirectory, "moresuits"); private void Awake() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"BM_Suits v1.5.0 initializing..."); SuitAudio.Initialize(); AdvancedSuitMaterials.Initialize(); Harmony val = new Harmony("com.brox.BM_Suits"); val.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"BM_Suits Harmony patches applied."); Log.LogInfo((object)"BM_Suits loaded successfully."); } } internal static class SuitAudio { private sealed class SoundGroup { internal readonly List<AudioClip> Clips = new List<AudioClip>(); private readonly Queue<int> shuffleQueue = new Queue<int>(); private int lastPlayedIndex = -1; internal int Count => Clips.Count; internal AudioClip First { get { if (Clips.Count == 0) { return null; } return Clips[0]; } } internal void Add(AudioClip clip) { if ((Object)(object)clip != (Object)null) { Clips.Add(clip); } } internal AudioClip GetClip(int index) { if (index < 0 || index >= Clips.Count) { return null; } return Clips[index]; } internal int GetNextIndex() { if (Clips.Count == 0) { return -1; } if (Clips.Count == 1) { lastPlayedIndex = 0; return 0; } if (shuffleQueue.Count == 0) { RebuildShuffle(); } return lastPlayedIndex = shuffleQueue.Dequeue(); } private void RebuildShuffle() { List<int> list = new List<int>(); for (int i = 0; i < Clips.Count; i++) { list.Add(i); } for (int num = list.Count - 1; num > 0; num--) { int index = Random.Range(0, num + 1); int value = list[num]; list[num] = list[index]; list[index] = value; } if (lastPlayedIndex >= 0 && list.Count > 1 && list[0] == lastPlayedIndex) { int index2 = Random.Range(1, list.Count); int value2 = list[0]; list[0] = list[index2]; list[index2] = value2; } foreach (int item in list) { shuffleQueue.Enqueue(item); } } } private sealed class PendingSuitUpSelection { internal ulong PlayerId; internal int SuitId; internal int ClipIndex; internal float Time; } private sealed class PendingSuitRpc { internal ulong PlayerId; internal int SuitId; internal float Time; } [HarmonyPatch(typeof(StartOfRound), "Start")] private static class StartOfRoundPatch { [HarmonyPostfix] private static void Postfix(StartOfRound __instance) { if (!((Object)(object)__instance == (Object)null)) { RegisterNetworkHandlers(); ((MonoBehaviour)__instance).StartCoroutine(LoadSoundsForRound(__instance)); } } } [HarmonyPatch(typeof(PlayerControllerB), "Jump_performed")] private static class JumpPatch { [HarmonyPrefix] private static void Prefix(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)(object)__instance)) { ChooseJumpSound(__instance); } } } [HarmonyPatch(typeof(UnlockableSuit), "SwitchSuitToThis")] private static class SuitSwitchPatch { [HarmonyPrefix] private static void Prefix(UnlockableSuit __instance, PlayerControllerB playerWhoTriggered) { if (!((Object)(object)__instance == (Object)null)) { PlayerControllerB val = playerWhoTriggered; if ((Object)(object)val == (Object)null && (Object)(object)GameNetworkManager.Instance != (Object)null) { val = GameNetworkManager.Instance.localPlayerController; } if (!((Object)(object)val == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)(object)val) && val.currentSuitID != __instance.suitID) { ChooseSuitUpSound(val, __instance.suitID); } } } } [HarmonyPatch(typeof(UnlockableSuit), "SwitchSuitClientRpc")] private static class SuitSwitchRpcPatch { [HarmonyPostfix] private static void Postfix(int playerID) { PrunePending(); } } private const string JumpRequestMessage = "BM_Suits.Jump.Request"; private const string JumpBroadcastMessage = "BM_Suits.Jump.Broadcast"; private const string SuitUpRequestMessage = "BM_Suits.SuitUp.Request"; private const string SuitUpBroadcastMessage = "BM_Suits.SuitUp.Broadcast"; private const float PendingEventLifetime = 5f; private static CustomMessagingManager registeredMessagingManager; private static readonly Dictionary<string, List<string>> jumpSoundPaths = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, List<string>> suitUpSoundPaths = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, SoundGroup> jumpSounds = new Dictionary<string, SoundGroup>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, SoundGroup> suitUpSounds = new Dictionary<string, SoundGroup>(StringComparer.OrdinalIgnoreCase); private static readonly List<PendingSuitUpSelection> pendingSuitUpSelections = new List<PendingSuitUpSelection>(); private static readonly List<PendingSuitRpc> pendingSuitRpcs = new List<PendingSuitRpc>(); private static readonly Regex soundFilePattern = new Regex("^(.*)_(Jump|SuitUp)(?:_(\\d+))?$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static ManualLogSource Logger => Plugin.Log; internal static void Initialize() { ScanSoundDirectory(); } private static void ScanSoundDirectory() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Invalid comparison between Unknown and I4 jumpSoundPaths.Clear(); suitUpSoundPaths.Clear(); if (!Directory.Exists(Plugin.SoundsDirectory)) { Directory.CreateDirectory(Plugin.SoundsDirectory); return; } string[] files = Directory.GetFiles(Plugin.SoundsDirectory, "*.*", SearchOption.TopDirectoryOnly); Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); int num = 0; int num2 = 0; string[] array = files; foreach (string path in array) { if ((int)GetAudioType(path) == 0) { continue; } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); Match match = soundFilePattern.Match(fileNameWithoutExtension); if (match.Success) { string value = match.Groups[1].Value; string value2 = match.Groups[2].Value; if (value2.Equals("Jump", StringComparison.OrdinalIgnoreCase)) { AddPath(jumpSoundPaths, value, path); num++; } else { AddPath(suitUpSoundPaths, value, path); num2++; } } } SortGroups(jumpSoundPaths); SortGroups(suitUpSoundPaths); Logger.LogInfo((object)("Found " + jumpSoundPaths.Count + " Jump group(s), " + num + " clip(s).")); Logger.LogInfo((object)("Found " + suitUpSoundPaths.Count + " SuitUp group(s), " + num2 + " clip(s).")); } private static void AddPath(Dictionary<string, List<string>> dictionary, string key, string path) { if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<string>()); } value.Add(path); } private static void SortGroups(Dictionary<string, List<string>> dictionary) { foreach (List<string> value in dictionary.Values) { value.Sort(StringComparer.OrdinalIgnoreCase); } } private static void RegisterNetworkHandlers() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.CustomMessagingManager != null) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; if (registeredMessagingManager != customMessagingManager) { registeredMessagingManager = customMessagingManager; TryUnregister(customMessagingManager, "BM_Suits.Jump.Request"); TryUnregister(customMessagingManager, "BM_Suits.Jump.Broadcast"); TryUnregister(customMessagingManager, "BM_Suits.SuitUp.Request"); TryUnregister(customMessagingManager, "BM_Suits.SuitUp.Broadcast"); customMessagingManager.RegisterNamedMessageHandler("BM_Suits.Jump.Request", new HandleNamedMessageDelegate(HandleJumpRequest)); customMessagingManager.RegisterNamedMessageHandler("BM_Suits.Jump.Broadcast", new HandleNamedMessageDelegate(HandleJumpBroadcast)); customMessagingManager.RegisterNamedMessageHandler("BM_Suits.SuitUp.Request", new HandleNamedMessageDelegate(HandleSuitUpRequest)); customMessagingManager.RegisterNamedMessageHandler("BM_Suits.SuitUp.Broadcast", new HandleNamedMessageDelegate(HandleSuitUpBroadcast)); Logger.LogInfo((object)"BM_Suits network handlers registered."); } } } private static void TryUnregister(CustomMessagingManager manager, string name) { try { manager.UnregisterNamedMessageHandler(name); } catch { } } private static IEnumerator LoadSoundsForRound(StartOfRound round) { yield return null; jumpSounds.Clear(); suitUpSounds.Clear(); foreach (KeyValuePair<string, List<string>> entry in jumpSoundPaths) { SoundGroup group = new SoundGroup(); foreach (string path in entry.Value) { AudioClip clip = null; yield return ((MonoBehaviour)round).StartCoroutine(LoadAudioClip(path, delegate(AudioClip result) { clip = result; })); if ((Object)(object)clip != (Object)null) { group.Add(clip); } } if (group.Count > 0) { jumpSounds[entry.Key] = group; } } foreach (KeyValuePair<string, List<string>> entry2 in suitUpSoundPaths) { SoundGroup group2 = new SoundGroup(); foreach (string path2 in entry2.Value) { AudioClip clip2 = null; yield return ((MonoBehaviour)round).StartCoroutine(LoadAudioClip(path2, delegate(AudioClip result) { clip2 = result; })); if ((Object)(object)clip2 != (Object)null) { group2.Add(clip2); } } if (group2.Count > 0) { suitUpSounds[entry2.Key] = group2; } } AssignInitialJumpAudio(round); Logger.LogInfo((object)("Audio ready: " + jumpSounds.Count + " Jump group(s) / " + CountClips(jumpSounds) + " clip(s), " + suitUpSounds.Count + " SuitUp group(s) / " + CountClips(suitUpSounds) + " clip(s).")); } private static int CountClips(Dictionary<string, SoundGroup> groups) { int num = 0; foreach (SoundGroup value in groups.Values) { num += value.Count; } return num; } private static void AssignInitialJumpAudio(StartOfRound round) { if ((Object)(object)round.unlockablesList == (Object)null || round.unlockablesList.unlockables == null) { return; } foreach (UnlockableItem unlockable in round.unlockablesList.unlockables) { if (unlockable != null && jumpSounds.TryGetValue(NormalizeSuitName(unlockable.unlockableName), out var value) && (Object)(object)value.First != (Object)null) { unlockable.jumpAudio = value.First; } } } private static void ChooseJumpSound(PlayerControllerB player) { UnlockableItem unlockable = GetUnlockable(player.currentSuitID); if (unlockable == null || !jumpSounds.TryGetValue(NormalizeSuitName(unlockable.unlockableName), out var value)) { return; } int nextIndex = value.GetNextIndex(); if (nextIndex >= 0) { AudioClip clip = value.GetClip(nextIndex); if (!((Object)(object)clip == (Object)null)) { unlockable.jumpAudio = clip; SendJumpSelection(player.playerClientId, player.currentSuitID, nextIndex); } } } private unsafe static void SendJumpSelection(ulong playerId, int suitId, int clipIndex) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening) { return; } RegisterNetworkHandlers(); if (singleton.IsServer) { BroadcastJumpSelection(playerId, suitId, clipIndex); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(32, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref playerId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref suitId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref clipIndex, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("BM_Suits.Jump.Request", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleJumpRequest(ulong sender, FastBufferReader reader) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsServer) { ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives)); int suitId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref suitId, default(ForPrimitives)); int clipIndex = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref clipIndex, default(ForPrimitives)); if (sender == num) { BroadcastJumpSelection(num, suitId, clipIndex); } } } private unsafe static void BroadcastJumpSelection(ulong playerId, int suitId, int clipIndex) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_007a: 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) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { return; } if (singleton.IsClient) { ApplyJumpSelection(suitId, clipIndex); } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(32, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref playerId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref suitId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref clipIndex, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessageToAll("BM_Suits.Jump.Broadcast", val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleJumpBroadcast(ulong sender, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0020: 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_0033: Unknown result type (might be due to invalid IL or missing references) ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives)); int suitId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref suitId, default(ForPrimitives)); int clipIndex = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref clipIndex, default(ForPrimitives)); ApplyJumpSelection(suitId, clipIndex); } private static void ApplyJumpSelection(int suitId, int clipIndex) { UnlockableItem unlockable = GetUnlockable(suitId); if (unlockable != null && jumpSounds.TryGetValue(NormalizeSuitName(unlockable.unlockableName), out var value)) { AudioClip clip = value.GetClip(clipIndex); if ((Object)(object)clip != (Object)null) { unlockable.jumpAudio = clip; } } } private static void ChooseSuitUpSound(PlayerControllerB player, int suitId) { UnlockableItem unlockable = GetUnlockable(suitId); if (unlockable != null && suitUpSounds.TryGetValue(NormalizeSuitName(unlockable.unlockableName), out var value)) { int nextIndex = value.GetNextIndex(); if (nextIndex >= 0) { SendSuitUpSelection(player.playerClientId, suitId, nextIndex); } } } private unsafe static void SendSuitUpSelection(ulong playerId, int suitId, int clipIndex) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening) { return; } RegisterNetworkHandlers(); if (singleton.IsServer) { BroadcastSuitUpSelection(playerId, suitId, clipIndex); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(32, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref playerId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref suitId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref clipIndex, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("BM_Suits.SuitUp.Request", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleSuitUpRequest(ulong sender, FastBufferReader reader) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsServer) { ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives)); int suitId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref suitId, default(ForPrimitives)); int clipIndex = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref clipIndex, default(ForPrimitives)); if (sender == num) { BroadcastSuitUpSelection(num, suitId, clipIndex); } } } private unsafe static void BroadcastSuitUpSelection(ulong playerId, int suitId, int clipIndex) { //IL_003e: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { return; } ApplySuitUpSelection(playerId, suitId, clipIndex); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(32, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref playerId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref suitId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref clipIndex, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessageToAll("BM_Suits.SuitUp.Broadcast", val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleSuitUpBroadcast(ulong sender, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0020: 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_0033: Unknown result type (might be due to invalid IL or missing references) ulong playerId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref playerId, default(ForPrimitives)); int suitId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref suitId, default(ForPrimitives)); int clipIndex = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref clipIndex, default(ForPrimitives)); ApplySuitUpSelection(playerId, suitId, clipIndex); } private static void ApplySuitUpSelection(ulong playerId, int suitId, int clipIndex) { PlayerControllerB player = GetPlayer(playerId); if ((Object)(object)player == (Object)null || (Object)(object)player.movementAudio == (Object)null) { return; } UnlockableItem unlockable = GetUnlockable(suitId); if (unlockable != null && suitUpSounds.TryGetValue(NormalizeSuitName(unlockable.unlockableName), out var value)) { AudioClip clip = value.GetClip(clipIndex); if (!((Object)(object)clip == (Object)null)) { player.movementAudio.PlayOneShot(clip); } } } private static PlayerControllerB GetPlayer(ulong playerId) { if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return null; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val != (Object)null && val.playerClientId == playerId) { return val; } } return null; } private static UnlockableItem GetUnlockable(int suitId) { if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.unlockablesList == (Object)null || StartOfRound.Instance.unlockablesList.unlockables == null) { return null; } List<UnlockableItem> unlockables = StartOfRound.Instance.unlockablesList.unlockables; if (suitId < 0 || suitId >= unlockables.Count) { return null; } return unlockables[suitId]; } private static void PrunePending() { float time = Time.time; for (int num = pendingSuitUpSelections.Count - 1; num >= 0; num--) { if (time - pendingSuitUpSelections[num].Time > 5f) { pendingSuitUpSelections.RemoveAt(num); } } for (int num2 = pendingSuitRpcs.Count - 1; num2 >= 0; num2--) { if (time - pendingSuitRpcs[num2].Time > 5f) { pendingSuitRpcs.RemoveAt(num2); } } } private static IEnumerator LoadAudioClip(string path, Action<AudioClip> callback) { AudioType type = GetAudioType(path); if ((int)type == 0) { callback(null); yield break; } string uri = new Uri(path).AbsoluteUri; UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(uri, type); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { callback(null); yield break; } AudioClip clip = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)clip != (Object)null) { ((Object)clip).name = Path.GetFileNameWithoutExtension(path); } callback(clip); } finally { ((IDisposable)request)?.Dispose(); } } private static AudioType GetAudioType(string path) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) return (AudioType)(Path.GetExtension(path).ToLowerInvariant() switch { ".ogg" => 14, ".wav" => 20, ".mp3" => 13, _ => 0, }); } private static string NormalizeSuitName(string value) { if (string.IsNullOrWhiteSpace(value)) { return value; } string text = value.Trim(); if (text.EndsWith(" suit", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - 5).TrimEnd(Array.Empty<char>()); } return text; } }