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 HaloScrap v1.1.3
BepInEx/plugins/HaloScrap/HaloScrap.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using HarmonyLib; using LethalLib.Modules; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("1.1.3.0")] namespace HaloScrap; [BepInPlugin("Clair.HaloScrap", "Halo Scrap", "1.1.3")] [BepInDependency("evaisa.lethallib", "1.2.0")] public sealed class Plugin : BaseUnityPlugin { internal sealed class Definition { public string Key; public string Name; public int Value; public int Rarity; public int Cap; public float Size; public Item Item; public Definition(string key, string name, int value, int rarity, int cap, float size) { Key = key; Name = name; Value = value; Rarity = rarity; Cap = cap; Size = size; } } [HarmonyPatch(typeof(GameNetworkManager), "Start")] private static class Registration { [HarmonyPrefix] private static void Prefix() { Initialize(); } } [HarmonyPatch(typeof(RoundManager), "GenerateNewLevelClientRpc")] private static class Visit { [HarmonyPrefix] private static void Prefix() { BeginVisit(); } } [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] private static class Spawn { [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = instructions.ToList(); int num = 0; int num2 = 0; foreach (CodeInstruction item in list) { MethodInfo methodInfo = item.operand as MethodInfo; if (methodInfo != null && methodInfo.DeclaringType == typeof(List<Item>) && methodInfo.Name == "Add") { item.opcode = OpCodes.Call; item.operand = AccessTools.Method(typeof(Plugin), "CappedAdd", (Type[])null, (Type[])null); num++; } else if (methodInfo != null && methodInfo.DeclaringType == typeof(Object) && methodInfo.Name == "Instantiate" && methodInfo.IsGenericMethod && methodInfo.GetGenericArguments()[0] == typeof(GameObject) && methodInfo.GetParameters().Length == 4) { item.opcode = OpCodes.Call; item.operand = AccessTools.Method(typeof(Plugin), "InstantiateScrap", (Type[])null, (Type[])null); num2++; } } if (num != 2 || num2 != 1) { throw new InvalidOperationException("Unsupported game SpawnScrapInLevel layout: " + num + " item selections, " + num2 + " instantiations. Halo Scrap caps cannot be guaranteed."); } return list; } } [HarmonyPatch(typeof(RoundManager), "SyncScrapValuesClientRpc")] private static class Values { [HarmonyPrefix] private static void Prefix(NetworkObjectReference[] spawnedScrap, int[] allScrapValue) { NetworkObject val = default(NetworkObject); for (int i = 0; i < Math.Min(spawnedScrap.Length, allScrapValue.Length); i++) { if (((NetworkObjectReference)(ref spawnedScrap[i])).TryGet(ref val, (NetworkManager)null)) { GrabbableObject component = ((Component)val).GetComponent<GrabbableObject>(); Definition definition = (Object.op_Implicit((Object)(object)component) ? Find(component.itemProperties) : null); if (definition != null) { allScrapValue[i] = definition.Value; } } } } } [HarmonyPatch(typeof(GrabbableObject), "Start")] private static class InitializeScanValue { [HarmonyPostfix] private static void Postfix(GrabbableObject __instance) { Definition definition = Find(__instance.itemProperties); if (definition != null) { __instance.SetScrapValue(definition.Value); } } } [HarmonyPatch(typeof(GrabbableObject), "SetScrapValue")] private static class ExactValue { [HarmonyPrefix] private static void Prefix(GrabbableObject __instance, ref int setValueTo) { Definition definition = Find(__instance.itemProperties); if (definition != null) { setValueTo = definition.Value; } } } internal static Plugin Instance; private static AssetBundle bundle; private static bool initialized; internal static readonly Definition[] Definitions = new Definition[7] { new Definition("FusionCoil", "Fusion Coil", 170, 28, int.MaxValue, 0.65f), new Definition("MA5C", "MA5C Assault Rifle", 65, 65, 3, 0.85f), new Definition("Warthog", "Warthog", 120, 8, int.MaxValue, 0.32f), new Definition("Claws", "Custom Halo Energy Claws", 120, 8, int.MaxValue, 0.65f), new Definition("EnergySword", "Halo 3 Energy Sword", 300, 1, 1, 1.05f), new Definition("SMG", "Halo 2 Anniversary SMG", 45, 65, 3, 0.55f), new Definition("ReconHelmet", "Recon Helmet", 70, 16, 2, 0.3f) }; private static readonly Dictionary<Item, int> visitCounts = new Dictionary<Item, int>(); private static bool swordEligible; private void Awake() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) Instance = this; bundle = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "haloscrap")); if (!Object.op_Implicit((Object)(object)bundle)) { throw new FileNotFoundException("Halo Scrap visual bundle missing or incompatible"); } new Harmony("Clair.HaloScrap").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Halo Scrap 1.1.3 loaded. Host and every player must install this version. Gameplay/multiplayer testing is user-performed."); } private static void BindGameMaterials(GameObject visual, Item template) { //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) Material val = template.spawnPrefab.GetComponentsInChildren<Renderer>(true).SelectMany((Renderer r) => r.sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m) && Object.op_Implicit((Object)(object)m.shader) && ((Object)m.shader).name == "HDRP/Lit" && m.shader.isSupported)); if (!Object.op_Implicit((Object)(object)val)) { val = (from i in Resources.FindObjectsOfTypeAll<Item>() where Object.op_Implicit((Object)(object)i.spawnPrefab) && i.isScrap select i).SelectMany((Item i) => i.spawnPrefab.GetComponentsInChildren<Renderer>(true)).SelectMany((Renderer r) => r.sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m) && Object.op_Implicit((Object)(object)m.shader) && ((Object)m.shader).name == "HDRP/Lit" && m.shader.isSupported && !((Object)m).name.StartsWith("HaloScrap_"))); } if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("No supported game-owned HDRP/Lit scrap material found. Refusing to create pink Halo Scrap."); } Renderer[] componentsInChildren = visual.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { Material[] sharedMaterials = val2.sharedMaterials; for (int num2 = 0; num2 < sharedMaterials.Length; num2++) { Material val3 = sharedMaterials[num2]; if (!Object.op_Implicit((Object)(object)val3)) { throw new InvalidDataException("Missing Halo material data"); } Texture val4 = (val3.HasProperty("_MainTex") ? val3.GetTexture("_MainTex") : val3.GetTexture("_BaseColorMap")); if (!Object.op_Implicit((Object)(object)val4)) { throw new InvalidDataException("Missing Halo albedo: " + ((Object)val3).name); } bool flag = ((Object)val3).name.StartsWith("HALO_EMISSIVE_"); Material val5 = new Material(val) { name = "HaloScrap_" + ((Object)val3).name }; val5.SetTexture("_BaseColorMap", val4); val5.SetColor("_BaseColor", Color.white); string[] array = new string[6] { "_NormalMap", "_MaskMap", "_DetailMap", "_BentNormalMap", "_HeightMap", "_CoatMaskMap" }; foreach (string text in array) { if (val5.HasProperty(text)) { val5.SetTexture(text, (Texture)null); } } val5.SetFloat("_Metallic", 0.25f); val5.SetFloat("_Smoothness", 0.3f); val5.SetColor("_EmissiveColor", flag ? (new Color(0.05f, 0.4f, 1f) * 2f) : Color.black); val5.SetTexture("_EmissiveColorMap", flag ? val4 : null); if (flag) { val5.EnableKeyword("_EMISSIVE_COLOR_MAP"); } else { val5.DisableKeyword("_EMISSIVE_COLOR_MAP"); } sharedMaterials[num2] = val5; } val2.sharedMaterials = sharedMaterials; } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("Material binding: " + ((Object)visual).name + " uses game-owned " + ((Object)val.shader).name + "; supported=" + val.shader.isSupported)); } internal static Definition Find(Item item) { return Definitions.FirstOrDefault((Definition x) => (Object)(object)x.Item == (Object)(object)item); } internal static void Initialize() { //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Expected O, but got Unknown //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) if (initialized) { return; } Item[] source = Resources.FindObjectsOfTypeAll<Item>(); Item val = ((IEnumerable<Item>)source).FirstOrDefault((Func<Item, bool>)((Item x) => x.isScrap && Object.op_Implicit((Object)(object)x.spawnPrefab) && (Object)(object)x.spawnPrefab.GetComponent<PhysicsProp>() != (Object)null)); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("No vanilla PhysicsProp scrap template is loaded. Cannot register Halo Scrap safely."); } Definition[] definitions = Definitions; foreach (Definition definition in definitions) { GameObject val2 = bundle.LoadAsset<GameObject>("Assets/Generated/" + definition.Key + ".prefab"); if (!Object.op_Implicit((Object)(object)val2)) { throw new InvalidDataException("Missing prefab " + definition.Key); } Item val3 = Object.Instantiate<Item>(val); ((Object)val3).name = "HaloScrap_" + definition.Key; val3.itemName = definition.Name; val3.isScrap = true; val3.minValue = definition.Value; val3.maxValue = definition.Value; val3.creditsWorth = definition.Value; val3.itemIcon = bundle.LoadAsset<Sprite>("Assets/Generated/" + definition.Key + "Icon.png"); if (!Object.op_Implicit((Object)(object)val3.itemIcon)) { throw new InvalidDataException("Missing unique model icon: " + definition.Key); } val3.weight = 1.05f; val3.twoHanded = false; val3.twoHandedAnimation = false; val3.requiresBattery = false; val3.isDefensiveWeapon = false; val3.itemSpawnsOnGround = true; val3.toolTips = new string[0]; val3.meshVariants = (Mesh[])(object)new Mesh[0]; val3.materialVariants = (Material[])(object)new Material[0]; val3.canBeInspected = false; val3.saveItemVariable = false; val3.rotationOffset = Vector3.zero; val3.positionOffset = new Vector3(0f, 0f, 0.1f); val3.restingRotation = Vector3.zero; val3.verticalOffset = 0.04f; val3.floorYOffset = 0; GameObject val4 = NetworkPrefabs.CreateNetworkPrefab("HaloScrap_" + definition.Key); val4.layer = LayerMask.NameToLayer("Props"); val4.tag = "PhysicsProp"; GameObject val5 = Object.Instantiate<GameObject>(val2, val4.transform); ((Object)val5).name = "HaloVisual"; BindGameMaterials(val5, val); Transform[] componentsInChildren = val5.GetComponentsInChildren<Transform>(true); foreach (Transform val6 in componentsInChildren) { ((Component)val6).gameObject.layer = val4.layer; } MeshRenderer[] componentsInChildren2 = val5.GetComponentsInChildren<MeshRenderer>(true); Bounds bounds = ((Renderer)componentsInChildren2[0]).bounds; MeshRenderer[] array = componentsInChildren2; foreach (MeshRenderer val7 in array) { ((Bounds)(ref bounds)).Encapsulate(((Renderer)val7).bounds); } BoxCollider val8 = val4.AddComponent<BoxCollider>(); val8.center = val4.transform.InverseTransformPoint(((Bounds)(ref bounds)).center); val8.size = ((Bounds)(ref bounds)).size; PhysicsProp val9 = val4.AddComponent<PhysicsProp>(); ((GrabbableObject)val9).itemProperties = val3; ((GrabbableObject)val9).grabbable = true; ((GrabbableObject)val9).grabbableToEnemies = true; ((GrabbableObject)val9).mainObjectRenderer = componentsInChildren2[0]; GameObject val10 = new GameObject("ScanNode"); val10.transform.SetParent(val4.transform, false); val10.transform.localPosition = val8.center; val10.layer = 22; if (LayerMask.NameToLayer("ScanNode") != 22) { throw new InvalidOperationException("Unexpected game ScanNode layer"); } BoxCollider val11 = val10.AddComponent<BoxCollider>(); val11.size = Vector3.one * 0.35f; ((Collider)val11).isTrigger = false; ScanNodeProperties val12 = val10.AddComponent<ScanNodeProperties>(); val12.headerText = definition.Name; val12.subText = "Value: $" + definition.Value; val12.scrapValue = definition.Value; val12.nodeType = 2; val12.minRange = 0; val12.maxRange = 13; val12.requiresLineOfSight = true; val12.creatureScanID = -1; val3.spawnPrefab = val4; definition.Item = val3; Items.RegisterScrap(val3, definition.Rarity, (LevelTypes)(-1)); ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("Registered " + definition.Name + " value=" + definition.Value + " rarity=" + definition.Rarity + " cap=" + definition.Cap)); } initialized = true; } internal static void BeginVisit() { visitCounts.Clear(); Random random = new Random(StartOfRound.Instance.randomMapSeed ^ 0x48414C4F); swordEligible = random.NextDouble() < 0.1; } public static void CappedAdd(List<Item> list, Item item) { Definition definition = Find(item); if (definition == null) { list.Add(item); return; } visitCounts.TryGetValue(item, out var value); if (value < definition.Cap && (!(definition.Key == "EnergySword") || swordEligible)) { visitCounts[item] = value + 1; list.Add(item); } } public static GameObject InstantiateScrap(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) { //IL_004d: 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_003f: 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_0045: Unknown result type (might be due to invalid IL or missing references) Definition definition = Definitions.FirstOrDefault((Definition x) => Object.op_Implicit((Object)(object)x.Item) && (Object)(object)x.Item.spawnPrefab == (Object)(object)prefab); if (definition != null && definition.Key == "EnergySword") { position = HiddenPosition(position); } return Object.Instantiate<GameObject>(prefab, position, rotation, parent); } private static Vector3 HiddenPosition(Vector3 fallback) { //IL_0065: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_00f9: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Invalid comparison between Unknown and I4 //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (from e in Object.FindObjectsOfType<EntranceTeleport>() where !e.isEntranceToBuilding select ((Component)e).transform.position).ToArray(); if (array.Length == 0) { return fallback; } Vector3 result = fallback; float num = float.MinValue; RandomScrapSpawn[] array2 = Object.FindObjectsOfType<RandomScrapSpawn>(); NavMeshHit val2 = default(NavMeshHit); foreach (RandomScrapSpawn val in array2) { if (val.spawnUsed || (Object)(object)val.spawnWithParent != (Object)null || !NavMesh.SamplePosition(((Component)val).transform.position, ref val2, 1.5f, -1)) { continue; } float num3 = float.MaxValue; bool flag = false; Vector3[] array3 = array; foreach (Vector3 val3 in array3) { NavMeshPath val4 = new NavMeshPath(); if (NavMesh.CalculatePath(val3, ((NavMeshHit)(ref val2)).position, -1, val4) && (int)val4.status <= 0) { flag = true; float num5 = 0f; for (int num6 = 1; num6 < val4.corners.Length; num6++) { num5 += Vector3.Distance(val4.corners[num6 - 1], val4.corners[num6]); } num3 = Mathf.Min(num3, num5); } } if (!flag) { continue; } int num7 = 0; Vector3[] array4 = array; foreach (Vector3 val5 in array4) { if (Physics.Linecast(val5 + Vector3.up, ((NavMeshHit)(ref val2)).position + Vector3.up, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1)) { num7++; } } float num9 = num3 + (float)(num7 * 15); if (num9 > num) { num = num9; result = ((NavMeshHit)(ref val2)).position + Vector3.up * 0.04f; } } return result; } }