Decompiled source of TwitchChatSpawner v1.0.0
TwitchChatSpawner.dll
Decompiled 16 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.ComponentModel; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FistVR; using HarmonyLib; using Sodalite; using Sodalite.Api; using Sodalite.ModPanel; using Sodalite.UiWidgets; using Steamworks; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; using UnityEngine.UI; [assembly: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace jediSpawner { public class ArmorSwitchPanel : MonoBehaviour { public Text FriendlySelection; public Text EnemyTypeSelection; public Text EnemySelection; public Text Status; public Button PreviousFriendly; public Button NextFriendly; public Button PreviousEnemyType; public Button NextEnemyType; public Button PreviousEnemy; public Button NextEnemy; public Button ApplyFriendly; public Button ApplyEnemy; public Button SpawnFriendly; public Button SpawnEnemy; public Button RandomArmorToggle; private ChatWatcher watcher; public void Bind(ChatWatcher owner) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown if (!((Object)(object)watcher != (Object)null)) { watcher = owner; ((UnityEvent)PreviousFriendly.onClick).AddListener((UnityAction)delegate { watcher.StepFriendlyArmor(-1); }); ((UnityEvent)NextFriendly.onClick).AddListener((UnityAction)delegate { watcher.StepFriendlyArmor(1); }); ((UnityEvent)PreviousEnemyType.onClick).AddListener((UnityAction)delegate { watcher.StepEnemyTemplate(-1); }); ((UnityEvent)NextEnemyType.onClick).AddListener((UnityAction)delegate { watcher.StepEnemyTemplate(1); }); ((UnityEvent)PreviousEnemy.onClick).AddListener((UnityAction)delegate { watcher.StepEnemyArmor(-1); }); ((UnityEvent)NextEnemy.onClick).AddListener((UnityAction)delegate { watcher.StepEnemyArmor(1); }); ((UnityEvent)ApplyFriendly.onClick).AddListener(new UnityAction(watcher.ApplyFriendlyArmorToAll)); ((UnityEvent)ApplyEnemy.onClick).AddListener(new UnityAction(watcher.ApplyEnemyArmorToAll)); ((UnityEvent)SpawnFriendly.onClick).AddListener(new UnityAction(watcher.SpawnFriendlyFromCurrentFile)); ((UnityEvent)SpawnEnemy.onClick).AddListener(new UnityAction(watcher.SpawnEnemyFromCurrentFile)); if ((Object)(object)RandomArmorToggle != (Object)null) { ((UnityEvent)RandomArmorToggle.onClick).AddListener(new UnityAction(watcher.ToggleRandomArmor)); } } } public void Refresh(ChatSpawner definition, int friendly, int enemyType, int enemy, string status, bool randomArmor) { Status.text = status; FriendlySelection.text = "FRIENDLY ARMOR\n" + ((!((Object)(object)definition == (Object)null)) ? definition.GetFriendlyOutfitName(friendly) : "Loading..."); EnemyTypeSelection.text = "ENEMY TYPE\n" + ((!((Object)(object)definition == (Object)null)) ? definition.GetEnemyTemplateName(enemyType) : "Loading..."); EnemySelection.text = "ENEMY ARMOR\n" + ((!((Object)(object)definition == (Object)null)) ? definition.GetEnemyOutfitName(enemyType, enemy) : "Loading..."); if (randomArmor) { FriendlySelection.text = "FRIENDLY ARMOR\nRandom T&H outfit"; EnemySelection.text = "ENEMY ARMOR\nRandom T&H outfit"; } if ((Object)(object)RandomArmorToggle != (Object)null) { ((Component)RandomArmorToggle).GetComponentInChildren<Text>().text = "RANDOM T&H ARMOR\n" + ((!randomArmor) ? "OFF" : "ON"); } bool flag = (Object)(object)definition != (Object)null && definition.GetFriendlyOutfitCount() > 0; bool flag2 = (Object)(object)definition != (Object)null && definition.GetEnemyTemplateCount() > 0; bool flag3 = flag2 && definition.GetEnemyOutfitCount(enemyType) > 0; Button previousFriendly = PreviousFriendly; bool interactable = flag && !randomArmor; ((Selectable)NextFriendly).interactable = interactable; ((Selectable)previousFriendly).interactable = interactable; ((Selectable)ApplyFriendly).interactable = (Object)(object)definition != (Object)null && (randomArmor || flag); Button previousEnemyType = PreviousEnemyType; interactable = flag2; ((Selectable)NextEnemyType).interactable = interactable; ((Selectable)previousEnemyType).interactable = interactable; Button previousEnemy = PreviousEnemy; interactable = flag3 && !randomArmor; ((Selectable)NextEnemy).interactable = interactable; ((Selectable)previousEnemy).interactable = interactable; ((Selectable)ApplyEnemy).interactable = (Object)(object)definition != (Object)null && (randomArmor || flag3); ((Selectable)SpawnFriendly).interactable = (Object)(object)definition != (Object)null; ((Selectable)SpawnEnemy).interactable = flag2; } } public class ChatSpawner : MonoBehaviour { public const int RandomArmorIndex = -2; private static readonly Dictionary<string, GameObject> resolvedObjectPrefabs = new Dictionary<string, GameObject>(); private static readonly HashSet<string> missingObjectWarnings = new HashSet<string>(); public SosigEnemyTemplate t; public List<SosigEnemyTemplate> EnemyT; public GameObject namething; public GameObject enemyNamePlate; [Tooltip("Custom UniversalModPanel canvas used by the armor-switching tablet.")] public GameObject ArmorPanelPrefab; public bool isEnemy = false; public float enemyIFF = 1f; public List<SosigOutfitConfig> GetAvailableArmorOutfits() { List<SosigOutfitConfig> list = new List<SosigOutfitConfig>(); HashSet<SosigOutfitConfig> hashSet = new HashSet<SosigOutfitConfig>(); IM val = Object.FindObjectOfType<IM>(); if ((Object)(object)val == (Object)null || val.odicSosigObjsByID == null) { return list; } foreach (SosigEnemyTemplate value in val.odicSosigObjsByID.Values) { if ((Object)(object)value == (Object)null || value.OutfitConfig == null) { continue; } foreach (SosigOutfitConfig item in value.OutfitConfig) { if ((Object)(object)item != (Object)null && HasArmorOptions(item) && hashSet.Add(item)) { list.Add(item); } } } return list; } public SosigOutfitConfig PickRandomArmor(List<SosigOutfitConfig> outfits) { return (outfits != null && outfits.Count != 0) ? outfits[Random.Range(0, outfits.Count)] : null; } private static bool HasArmorOptions(SosigOutfitConfig outfit) { return HasArmorOptions(outfit.Headwear, outfit.Chance_Headwear) || HasArmorOptions(outfit.Facewear, outfit.Chance_Facewear) || HasArmorOptions(outfit.Eyewear, outfit.Chance_Eyewear) || HasArmorOptions(outfit.Torsowear, outfit.Chance_Torsowear) || HasArmorOptions(outfit.Pantswear, outfit.Chance_Pantswear) || HasArmorOptions(outfit.Pantswear_Lower, outfit.Chance_Pantswear_Lower) || HasArmorOptions(outfit.Backpacks, outfit.Chance_Backpacks) || HasArmorOptions(outfit.TorosDecoration, outfit.Chance_TorosDecoration); } private static bool HasArmorOptions(List<FVRObject> pieces, float chance) { if (pieces == null || chance <= 0f) { return false; } for (int i = 0; i < pieces.Count; i++) { if ((Object)(object)pieces[i] != (Object)null) { return true; } } return false; } public void SpawningSequence() { SpawningSequence(-1); } public Sosig SpawningSequence(int outfitIndex) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) int num = ((!((Object)(object)GM.CurrentPlayerBody == (Object)null)) ? GM.CurrentPlayerBody.GetPlayerIFF() : 0); Sosig val = SpawnFromTemplate(t, ((Component)this).transform.position, ((Component)this).transform.rotation, num, outfitIndex); if ((Object)(object)val == (Object)null) { return null; } val.SetIFF(num); val.SetOriginalIFFTeam(num); val.DoesAggroOnFriendlyFire = false; if ((Object)(object)GM.CurrentPlayerBody != (Object)null && (Object)(object)GM.CurrentPlayerBody.Head != (Object)null) { val.CommandAssaultPoint(GetFriendlyFollowPoint()); val.SetCurrentOrder((SosigOrder)7); } val.FallbackOrder = (SosigOrder)4; AttachNamePlate((!((Object)(object)namething == (Object)null)) ? namething : enemyNamePlate, val, isEnemyNamePlate: false); ChatWatcher.RegisterFriendly(val); return val; } public void SpawningSequenceEnemy(int iff) { SpawningSequenceEnemy(iff, -1, -1); } public Sosig SpawningSequenceEnemy(int iff, int templateIndex, int outfitIndex) { //IL_0011: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) SosigEnemyTemplate enemyTemplate = GetEnemyTemplate(templateIndex); Sosig val = SpawnFromTemplate(enemyTemplate, ((Component)this).transform.position, ((Component)this).transform.rotation, iff, outfitIndex); if ((Object)(object)val == (Object)null) { return null; } if ((Object)(object)GM.CurrentPlayerBody != (Object)null) { val.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position); val.SetCurrentOrder((SosigOrder)7); } val.FallbackOrder = (SosigOrder)4; AttachNamePlate(enemyNamePlate, val, isEnemyNamePlate: true); ChatWatcher.RegisterEnemy(val); return val; } public Sosig SpawningSequenceBoss(int iff, int templateIndex, int outfitIndex, float healthMultiplier, float scaleMultiplier, float speedMultiplier) { //IL_0011: 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_0078: 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) SosigEnemyTemplate enemyTemplate = GetEnemyTemplate(templateIndex); Sosig val = SpawnFromTemplate(enemyTemplate, ((Component)this).transform.position, ((Component)this).transform.rotation, iff, outfitIndex); if ((Object)(object)val == (Object)null) { return null; } ApplyBossModifiers(val, healthMultiplier, scaleMultiplier, speedMultiplier); if ((Object)(object)GM.CurrentPlayerBody != (Object)null) { val.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position); val.SetCurrentOrder((SosigOrder)7); } val.FallbackOrder = (SosigOrder)4; AttachNamePlate(enemyNamePlate, val, isEnemyNamePlate: true); ChatWatcher.RegisterEnemy(val); ChatWatcher.RegisterBoss(val); return val; } public int GetFriendlyOutfitCount() { return (!((Object)(object)t == (Object)null) && t.OutfitConfig != null) ? t.OutfitConfig.Count : 0; } public string GetFriendlyOutfitName(int index) { SosigOutfitConfig outfit = GetOutfit(t, index); return (!((Object)(object)outfit == (Object)null)) ? CleanAssetName(((Object)outfit).name) : "None"; } public int GetEnemyTemplateCount() { return GetUniqueEnemyTemplates().Count; } public string GetEnemyTemplateName(int index) { SosigEnemyTemplate enemyTemplate = GetEnemyTemplate(index); return (!((Object)(object)enemyTemplate == (Object)null)) ? CleanAssetName(((Object)enemyTemplate).name) : "None"; } public int GetEnemyOutfitCount(int templateIndex) { SosigEnemyTemplate enemyTemplate = GetEnemyTemplate(templateIndex); return (!((Object)(object)enemyTemplate == (Object)null) && enemyTemplate.OutfitConfig != null) ? enemyTemplate.OutfitConfig.Count : 0; } public string GetEnemyOutfitName(int templateIndex, int outfitIndex) { SosigOutfitConfig outfit = GetOutfit(GetEnemyTemplate(templateIndex), outfitIndex); return (!((Object)(object)outfit == (Object)null)) ? CleanAssetName(((Object)outfit).name) : "None"; } public SosigEnemyTemplate GetEnemyTemplate(int index) { List<SosigEnemyTemplate> uniqueEnemyTemplates = GetUniqueEnemyTemplates(); if (uniqueEnemyTemplates.Count == 0) { return null; } if (index < 0 || index >= uniqueEnemyTemplates.Count) { return uniqueEnemyTemplates[Random.Range(0, uniqueEnemyTemplates.Count)]; } return uniqueEnemyTemplates[index]; } public List<SosigEnemyTemplate> GetUniqueEnemyTemplates() { List<SosigEnemyTemplate> list = new List<SosigEnemyTemplate>(); if (EnemyT == null) { return list; } for (int i = 0; i < EnemyT.Count; i++) { SosigEnemyTemplate val = EnemyT[i]; if ((Object)(object)val != (Object)null && !list.Contains(val)) { list.Add(val); } } return list; } public SosigOutfitConfig GetOutfit(SosigEnemyTemplate template, int index) { if ((Object)(object)template == (Object)null || template.OutfitConfig == null || template.OutfitConfig.Count == 0) { return null; } if (index < 0 || index >= template.OutfitConfig.Count) { return template.OutfitConfig[Random.Range(0, template.OutfitConfig.Count)]; } return template.OutfitConfig[index]; } public bool ApplyOutfit(Sosig sosig, SosigOutfitConfig outfit, bool removeCurrentArmor) { if ((Object)(object)sosig == (Object)null || (Object)(object)outfit == (Object)null || sosig.Links == null || sosig.Links.Count < 4) { return false; } SosigWearable[] array = ((!removeCurrentArmor) ? null : ((Component)sosig).GetComponentsInChildren<SosigWearable>(true)); int num = 0; if (TrySpawnAccessory(outfit.Headwear, outfit.Chance_Headwear, sosig.Links[0])) { num++; } if (TrySpawnAccessory(outfit.Facewear, outfit.Chance_Facewear, sosig.Links[0])) { num++; } if (TrySpawnAccessory(outfit.Eyewear, outfit.Chance_Eyewear, sosig.Links[0])) { num++; } if (TrySpawnAccessory(outfit.Torsowear, outfit.Chance_Torsowear, sosig.Links[1])) { num++; } if (TrySpawnAccessory(outfit.Pantswear, outfit.Chance_Pantswear, sosig.Links[2])) { num++; } if (TrySpawnAccessory(outfit.Pantswear_Lower, outfit.Chance_Pantswear_Lower, sosig.Links[3])) { num++; } if (TrySpawnAccessory(outfit.Backpacks, outfit.Chance_Backpacks, sosig.Links[1])) { num++; } if (TrySpawnAccessory(outfit.TorosDecoration, outfit.Chance_TorosDecoration, sosig.Links[1])) { num++; } if (num == 0) { Debug.LogWarning((object)("[Twitch Chat Spawner] No loadable armor pieces were found for outfit " + ((Object)outfit).name)); } else if (array != null) { RemoveWearables(array); } return num > 0; } public void RemoveCurrentArmor(Sosig sosig) { if (!((Object)(object)sosig == (Object)null)) { RemoveWearables(((Component)sosig).GetComponentsInChildren<SosigWearable>(true)); } } private void RemoveWearables(SosigWearable[] wearables) { foreach (SosigWearable val in wearables) { if (!((Object)(object)val == (Object)null)) { if ((Object)(object)val.L != (Object)null) { val.L.DeRegisterWearable(val); } ((Component)val).transform.SetParent((Transform)null); Object.Destroy((Object)(object)((Component)val).gameObject); } } } private static void ApplyBossModifiers(Sosig boss, float healthMultiplier, float scaleMultiplier, float speedMultiplier) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) healthMultiplier = Mathf.Clamp(healthMultiplier, 1f, 25f); scaleMultiplier = Mathf.Clamp(scaleMultiplier, 1f, 2f); speedMultiplier = Mathf.Clamp(speedMultiplier, 0.5f, 2f); ((Component)boss).transform.localScale = ((Component)boss).transform.localScale * scaleMultiplier; for (int i = 0; i < boss.Links.Count; i++) { SosigLink val = boss.Links[i]; if (!((Object)(object)val == (Object)null)) { val.m_fullintegrity *= healthMultiplier; val.m_integrity = val.m_fullintegrity; } } float num = Mathf.Sqrt(healthMultiplier); boss.StunThreshold *= num; boss.StunMultiplier /= num; boss.BleedDamageMult /= num; boss.BleedRateMult /= num; boss.Speed_Crawl *= speedMultiplier; boss.Speed_Sneak *= speedMultiplier; boss.Speed_Walk *= speedMultiplier; boss.Speed_Run *= speedMultiplier; boss.Speed_Turning *= speedMultiplier; } private Sosig SpawnFromTemplate(SosigEnemyTemplate template, Vector3 position, Quaternion rotation, int iff, int outfitIndex) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_014a: 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) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0194: 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) SosigEnemyTemplate val = template; template = ResolveRuntimeTemplate(template); if (!IsUsableTemplate(template)) { Debug.LogError((object)"[Twitch Chat Spawner] The selected Sosig template is incomplete and no runtime template was available."); return null; } GameObject randomObject = GetRandomObject(template.SosigPrefabs); if ((Object)(object)randomObject == (Object)null) { Debug.LogError((object)"[Twitch Chat Spawner] The selected Sosig template has no resolved prefab."); return null; } GameObject val2 = Object.Instantiate<GameObject>(randomObject, position, rotation); Sosig componentInChildren = val2.GetComponentInChildren<Sosig>(); if ((Object)(object)componentInChildren == (Object)null) { Object.Destroy((Object)(object)val2); return null; } SosigConfigTemplate val3 = template.ConfigTemplates[Random.Range(0, template.ConfigTemplates.Count)]; componentInChildren.Configure(val3); componentInChildren.SetIFF(iff); componentInChildren.SetOriginalIFFTeam(iff); if ((Object)(object)componentInChildren.E != (Object)null) { componentInChildren.E.IFFCode = iff; } if (componentInChildren.Priority != null && componentInChildren.Priority.IFFChart != null) { for (int i = 0; i < componentInChildren.Priority.IFFChart.Length; i++) { componentInChildren.Priority.IFFChart[i] = i != iff; } } componentInChildren.Inventory.Init(); EquipWeapon(componentInChildren, GetRandomObject(template.WeaponOptions), position, rotation, initializeHands: true); if (Random.value <= template.SecondaryChance) { EquipWeapon(componentInChildren, GetRandomObject(template.WeaponOptions_Secondary), position, rotation, initializeHands: false); } if (Random.value <= template.TertiaryChance) { EquipWeapon(componentInChildren, GetRandomObject(template.WeaponOptions_Tertiary), position, rotation, initializeHands: false); } componentInChildren.Inventory.FillAllAmmo(); SosigOutfitConfig val4 = ((outfitIndex != -2) ? GetOutfit(val, outfitIndex) : PickRandomArmor(GetAvailableArmorOutfits())); if (outfitIndex == -2 && (Object)(object)val4 == (Object)null) { Debug.LogWarning((object)"[Twitch Chat Spawner] Runtime armor catalog is unavailable; using the spawn template outfit."); } if ((Object)(object)val4 == (Object)null) { val4 = GetOutfit(template, outfitIndex); } if (!ApplyOutfit(componentInChildren, val4, removeCurrentArmor: false) && (Object)(object)val != (Object)(object)template) { SosigOutfitConfig outfit = GetOutfit(template, -1); if ((Object)(object)outfit != (Object)null && (Object)(object)outfit != (Object)(object)val4) { Debug.LogWarning((object)"[Twitch Chat Spawner] Using runtime H3VR armor because the selected custom outfit could not be loaded."); ApplyOutfit(componentInChildren, outfit, removeCurrentArmor: false); } } RegisterLinkSpawns(componentInChildren, val3); return componentInChildren; } private static SosigEnemyTemplate ResolveRuntimeTemplate(SosigEnemyTemplate template) { //IL_0051: 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) if (HasResolvedSosigPrefab(template)) { return template; } if ((Object)(object)template == (Object)null) { return null; } IM val = Object.FindObjectOfType<IM>(); if ((Object)(object)val == (Object)null || val.odicSosigObjsByID == null) { return template; } if (val.odicSosigObjsByID.TryGetValue(template.SosigEnemyID, out var value) && HasResolvedSosigPrefab(value)) { Debug.Log((object)("[Twitch Chat Spawner] Resolved missing Sosig prefab from H3VR template " + template.SosigEnemyID)); return value; } return template; } private static bool HasResolvedSosigPrefab(SosigEnemyTemplate template) { if ((Object)(object)template == (Object)null || template.SosigPrefabs == null || template.SosigPrefabs.Count == 0) { return false; } for (int i = 0; i < template.SosigPrefabs.Count; i++) { if ((Object)(object)template.SosigPrefabs[i] != (Object)null) { return true; } } return false; } private static bool IsUsableTemplate(SosigEnemyTemplate template) { return (Object)(object)template != (Object)null && template.SosigPrefabs != null && template.SosigPrefabs.Count > 0 && template.ConfigTemplates != null && template.ConfigTemplates.Count > 0; } private static GameObject GetRandomObject(List<FVRObject> objects) { if (objects == null || objects.Count == 0) { return null; } FVRObject val = objects[Random.Range(0, objects.Count)]; return (!((Object)(object)val == (Object)null)) ? ((AnvilAsset)val).GetGameObject() : null; } private static void EquipWeapon(Sosig sosig, GameObject prefab, Vector3 position, Quaternion rotation, bool initializeHands) { //IL_001f: 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_002a: 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_0034: 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_009e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sosig == (Object)null || (Object)(object)prefab == (Object)null) { return; } GameObject val = Object.Instantiate<GameObject>(prefab, position + Vector3.up * 0.1f, rotation); SosigWeapon component = val.GetComponent<SosigWeapon>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val); return; } component.SetAutoDestroy(true); if ((Object)(object)component.O != (Object)null) { component.O.SpawnLockable = false; } component.SetAmmoClamping(true); component.IsShakeReloadable = false; if ((int)component.Type == 0) { sosig.Inventory.FillAmmoWithType(component.AmmoType); } if (initializeHands) { sosig.InitHands(); } sosig.ForceEquip(component); } private bool TrySpawnAccessory(List<FVRObject> accessories, float chance, SosigLink link) { //IL_0095: 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) if ((Object)(object)link == (Object)null || accessories == null || accessories.Count == 0 || Random.value >= chance) { return false; } int num = Random.Range(0, accessories.Count); for (int i = 0; i < accessories.Count; i++) { FVRObject val = accessories[(num + i) % accessories.Count]; if ((Object)(object)val == (Object)null) { continue; } GameObject val2 = ResolveObjectPrefab(val); if ((Object)(object)val2 == (Object)null) { WarnMissingObjectOnce(val, "could not resolve its prefab"); continue; } GameObject val3 = Object.Instantiate<GameObject>(val2, ((Component)link).transform.position, ((Component)link).transform.rotation); SosigWearable component = val3.GetComponent<SosigWearable>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val3); WarnMissingObjectOnce(val, "does not contain a SosigWearable component"); continue; } val3.transform.SetParent(((Component)link).transform); component.RegisterWearable(link); return true; } return false; } private static GameObject ResolveObjectPrefab(FVRObject selected) { string text = ((!string.IsNullOrEmpty(selected.ItemID)) ? selected.ItemID : ((Object)selected).name); if (!string.IsNullOrEmpty(text) && resolvedObjectPrefabs.TryGetValue(text, out var value) && (Object)(object)value != (Object)null) { return value; } string assetName = ((AnvilAsset)selected).m_anvilPrefab.AssetName; if (!string.IsNullOrEmpty(assetName)) { int num = Mathf.Max(assetName.LastIndexOf('/'), assetName.LastIndexOf('\\')); string text2 = ((num < 0) ? assetName : assetName.Substring(num + 1)); if (text2.EndsWith(".prefab")) { text2 = text2.Substring(0, text2.Length - 7); } GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, text2)) { return CacheObjectPrefab(text, val); } } } if (!string.IsNullOrEmpty(selected.ItemID) && IM.OD != null && IM.OD.TryGetValue(selected.ItemID, out var value2) && (Object)(object)value2 != (Object)null && (Object)(object)value2 != (Object)(object)selected) { GameObject gameObject = ((AnvilAsset)value2).GetGameObject(); if ((Object)(object)gameObject != (Object)null) { return CacheObjectPrefab(text, gameObject); } } GameObject gameObject2 = ((AnvilAsset)selected).GetGameObject(); if ((Object)(object)gameObject2 != (Object)null) { return CacheObjectPrefab(text, gameObject2); } return null; } private static GameObject CacheObjectPrefab(string key, GameObject prefab) { if (!string.IsNullOrEmpty(key) && (Object)(object)prefab != (Object)null) { resolvedObjectPrefabs[key] = prefab; } return prefab; } private static void WarnMissingObjectOnce(FVRObject selected, string reason) { string text = (((Object)(object)selected == (Object)null) ? "unknown armor piece" : ((!string.IsNullOrEmpty(selected.ItemID)) ? selected.ItemID : ((Object)selected).name)); string item = text + ":" + reason; if (missingObjectWarnings.Add(item)) { Debug.LogWarning((object)("[Twitch Chat Spawner] Skipping armor piece " + text + " because it " + reason + ".")); } } private static void RegisterLinkSpawns(Sosig sosig, SosigConfigTemplate config) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Invalid comparison between Unknown and I4 if ((Object)(object)sosig == (Object)null || (Object)(object)config == (Object)null || !config.UsesLinkSpawns || config.LinkSpawns == null || config.LinkSpawnChance == null) { return; } int num = Mathf.Min(sosig.Links.Count, Mathf.Min(config.LinkSpawns.Count, config.LinkSpawnChance.Count)); for (int i = 0; i < num; i++) { FVRObject val = config.LinkSpawns[i]; if ((Object)(object)val != (Object)null && (int)val.Category != 50 && Random.value < config.LinkSpawnChance[i]) { sosig.Links[i].RegisterSpawnOnDestroy(val); } } } private static Vector3 GetFriendlyFollowPoint() { //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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) Vector3 position = GM.CurrentPlayerBody.Head.position; float num = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f); float num2 = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f); return new Vector3(position.x + num, position.y, position.z + num2); } private static void AttachNamePlate(GameObject namePlatePrefab, Sosig sosig, bool isEnemyNamePlate) { //IL_0059: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00df: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)namePlatePrefab == (Object)null || (Object)(object)sosig == (Object)null || sosig.Links == null || sosig.Links.Count < 1) { return; } GameObject val = Object.Instantiate<GameObject>(namePlatePrefab, ((Component)sosig.Links[0]).transform, false); val.transform.localPosition = Vector3.up * 0.45f; val.transform.localRotation = Quaternion.identity; string text = ((!((Object)(object)ChatWatcher.instance == (Object)null)) ? ChatWatcher.instance.SpawnerName : "Chatter"); Color val2 = ((!isEnemyNamePlate) ? new Color(0.2f, 1f, 0.2f, 1f) : new Color(1f, 0.15f, 0.15f, 1f)); Text[] componentsInChildren = val.GetComponentsInChildren<Text>(true); Material val3 = null; for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = text; ((Graphic)componentsInChildren[i]).color = val2; if ((Object)(object)val3 == (Object)null && (Object)(object)((Graphic)componentsInChildren[i]).material != (Object)null) { val3 = new Material(((Graphic)componentsInChildren[i]).material); if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", val2); } if (val3.HasProperty("_MainColor")) { val3.SetColor("_MainColor", val2); } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", val2); } } if ((Object)(object)val3 != (Object)null) { ((Graphic)componentsInChildren[i]).material = val3; } } } private static string CleanAssetName(string value) { if (string.IsNullOrEmpty(value)) { return "Unnamed"; } return value.Replace("Jedi", string.Empty).Replace("Outfit", string.Empty).Trim(); } public void EmotionalConnection(GameObject nameBox, Sosig sosig, bool enemy) { AttachNamePlate(nameBox, sosig, enemy); } public void EmotionalConnectionButEvil(GameObject nameBox, Sosig sosig, bool enemy) { AttachNamePlate(nameBox, sosig, isEnemyNamePlate: true); } } [BepInPlugin("h3vr.arpy.chatspawner", "Twitch Chat Spawner", "2.1.0")] [BepInDependency("nrgill28.Sodalite", "1.5.1")] [BepInProcess("h3vr.exe")] public class ChatWatcher : BaseUnityPlugin { private sealed class SosigMovementState { public Vector3 LastPosition; public float LastMovementTime; public SosigMovementState(Vector3 position, float time) { //IL_0008: 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) LastPosition = position; LastMovementTime = time; } } private sealed class FriendlyShot { public readonly Vector3 Origin; public readonly float ExpiresAt; public FriendlyShot(Vector3 origin, float expiresAt) { //IL_0008: 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) Origin = origin; ExpiresAt = expiresAt; } } public static ChatWatcher instance; public static List<Sosig> spawnedChatters = new List<Sosig>(); public static List<Sosig> spawnedEnemyChatters = new List<Sosig>(); public static List<Sosig> spawnedBosses = new List<Sosig>(); private static readonly string BasePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); private static LayerMask environmentMask; private static readonly List<FriendlyShot> recentFriendlyShots = new List<FriendlyShot>(); private static readonly string[] FriendlyFallbackNames = new string[10] { "Bun Backup", "Captain Ketchup", "Chat Pal", "Cover Sausage", "Helpful Frank", "Hotdog Hero", "Mustard Medic", "Rescue Weiner", "Sir Snacks", "Tactical Tater" }; private static readonly string[] EnemyFallbackNames = new string[10] { "Angry Frank", "Baron Bratwurst", "Chat Menace", "Colonel Crispy", "Danger Dog", "Hostile Hotdog", "Major Mustard", "Sneaky Sausage", "The Heckler", "Wurst Enemy" }; private static readonly string[] BossFallbackNames = new string[10] { "Big Bad Brat", "Boss Beefcake", "Chat Overlord", "Duke of Damage", "Final Frank", "King Ketchup", "Lord Longdog", "Mega Meat", "Supreme Sausage", "The Big Weiner" }; private ConfigEntry<FileInfo> friendlyNameFile; private ConfigEntry<FileInfo> enemyNameFile; private ConfigEntry<FileInfo> bossNameFile; private ConfigEntry<KeyCode> friendlySpawnKey; private ConfigEntry<KeyCode> enemySpawnKey; private ConfigEntry<KeyCode> bossSpawnKey; private ConfigEntry<bool> autoSpawnFriendly; private ConfigEntry<bool> autoSpawnEnemy; private ConfigEntry<bool> autoSpawnBoss; private ConfigEntry<float> filePollSeconds; private ConfigEntry<int> maxLivingPerTeam; private ConfigEntry<int> fallbackEnemyIFF; private ConfigEntry<bool> protectStreamer; private ConfigEntry<float> streamerSafetyRadius; private ConfigEntry<bool> preserveChatSosigsInTakeAndHold; private ConfigEntry<int> maxActiveBosses; private ConfigEntry<float> bossHealthMultiplier; private ConfigEntry<float> bossScaleMultiplier; private ConfigEntry<float> bossSpeedMultiplier; private ConfigEntry<bool> useSteamFriendsAsFallback; private ConfigEntry<bool> onlineSteamFriendsOnly; private ConfigEntry<bool> randomArmor; private ConfigEntry<float> steamFriendRefreshSeconds; private GameObject prefabToSpawn; private ChatSpawner prefabDefinition; private readonly List<WristMenuButton> wristButtons = new List<WristMenuButton>(); private LockablePanel controlPanel; private LockablePanel armorPanel; private ArmorSwitchPanel armorPanelUi; private TextWidget panelStatusText; private TextWidget panelCountText; private TextWidget panelSelectionText; private ButtonWidget panelFriendlyArmorButton; private ButtonWidget panelEnemyTemplateButton; private ButtonWidget panelEnemyArmorButton; private ButtonWidget panelAutoFriendlyButton; private ButtonWidget panelAutoEnemyButton; private ButtonWidget panelAutoBossButton; private ButtonWidget panelProtectionButton; private string panelStatus = "Ready"; private float nextFilePoll; private float nextSosigUpdate; private float nextFriendlyFireCheck; private long friendlyWriteTicks; private long enemyWriteTicks; private long bossWriteTicks; private int friendlyArmorIndex; private int enemyTemplateIndex; private int enemyArmorIndex; private int previousLivingBossCount; private readonly Dictionary<Sosig, float> blockedFriendlySince = new Dictionary<Sosig, float>(); private readonly Dictionary<Sosig, SosigMovementState> movementStates = new Dictionary<Sosig, SosigMovementState>(); private readonly List<string> steamFriendNames = new List<string>(); private Harmony harmony; private int steamFriendIndex = -1; private float nextSteamFriendRefresh; public string SpawnerName = "Chatter"; public TNH_Manager TNHManager; public int enemyIFF = 3; public void Awake() { //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) instance = this; spawnedChatters = new List<Sosig>(); spawnedEnemyChatters = new List<Sosig>(); spawnedBosses = new List<Sosig>(); recentFriendlyShots.Clear(); movementStates.Clear(); EnsureDefaultChatDirectory(); RegisterFilePathConverter(); friendlyNameFile = ((BaseUnityPlugin)this).Config.Bind<FileInfo>("Chat files", "Friendly name file", new FileInfo(Path.Combine(Paths.ConfigPath, Path.Combine("TwitchChatSpawner", "friendly.txt"))), "File path to the text, JSON, or INI file written by LioranBoard for friendly viewer names."); enemyNameFile = ((BaseUnityPlugin)this).Config.Bind<FileInfo>("Chat files", "Enemy name file", new FileInfo(Path.Combine(Paths.ConfigPath, Path.Combine("TwitchChatSpawner", "enemy.txt"))), "File path to the text, JSON, or INI file written by LioranBoard for enemy viewer names."); bossNameFile = ((BaseUnityPlugin)this).Config.Bind<FileInfo>("Chat files", "Boss name file", new FileInfo(Path.Combine(Paths.ConfigPath, Path.Combine("TwitchChatSpawner", "boss.txt"))), "File path to the text, JSON, or INI file written by LioranBoard when a viewer becomes the boss."); autoSpawnFriendly = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat files", "Auto-spawn friendlies", false, "Spawn a friendly whenever the friendly name file changes."); autoSpawnEnemy = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat files", "Auto-spawn enemies", false, "Spawn an enemy whenever the enemy name file changes."); autoSpawnBoss = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat files", "Auto-spawn bosses", false, "Spawn a boss whenever the boss name file changes. Only the configured number of bosses may live at once."); filePollSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Chat files", "Poll interval seconds", 0.5f, "How often to check the chat name files for a new viewer."); useSteamFriendsAsFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("Steam friends", "Use friends without chat files", true, "When a chat name file is missing or empty, cycle through your Steam friends instead of using a generic name."); onlineSteamFriendsOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Steam friends", "Online friends only", false, "Only use friends who are currently online. Turn this off to include the full friends list."); randomArmor = ((BaseUnityPlugin)this).Config.Bind<bool>("Armor", "Random T&H armor", true, "Pick a complete outfit independently for each chat Sosig from the game's registered enemy templates. Includes custom registered outfits. Applies to allies, enemies, and bosses."); steamFriendRefreshSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Steam friends", "Refresh interval seconds", 60f, "How often the locally cached Steam friends list may be refreshed."); friendlySpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "Friendly spawn key", (KeyCode)112, "Keyboard shortcut for spawning a friendly chatter."); enemySpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "Enemy spawn key", (KeyCode)263, "Keyboard shortcut for spawning an enemy chatter."); bossSpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "Boss spawn key", (KeyCode)98, "Keyboard shortcut for spawning the current chat viewer as a boss."); maxLivingPerTeam = ((BaseUnityPlugin)this).Config.Bind<int>("Safety", "Maximum living per team", 30, "Stops chat events from spawning too many Sosigs. Use 0 for unlimited."); fallbackEnemyIFF = ((BaseUnityPlugin)this).Config.Bind<int>("Safety", "Enemy IFF outside Take and Hold", 3, "IFF used when an enemy is spawned outside Take and Hold."); protectStreamer = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "Protect streamer from friendly fire", true, "Stops friendly guns when the player is directly between a friendly and its target."); streamerSafetyRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "Streamer firing-lane radius", 0.8f, "Width in metres of the protected firing lane around the player's head and torso."); preserveChatSosigsInTakeAndHold = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "Preserve chat Sosigs during Take and Hold cleanup", true, "Keeps living chat-spawned allies, enemies, and bosses when a hold clears ordinary Sosigs. Dead chat Sosigs still clean up normally."); maxActiveBosses = ((BaseUnityPlugin)this).Config.Bind<int>("Boss", "Maximum active bosses", 1, "Maximum number of living chat bosses allowed at once."); bossHealthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Boss", "Health multiplier", 6f, "Multiplies the integrity of every boss body link."); bossScaleMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Boss", "Scale multiplier", 1.25f, "Makes the boss visually larger. Values above 1.5 may cause physics problems."); bossSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Boss", "Speed multiplier", 1.1f, "Multiplies the boss movement speeds."); InstallRuntimePatches(); TryResolveSpawnerPrefab(); environmentMask = LayerMask.op_Implicit(LayerMask.GetMask(new string[1] { "Environment" })); SeedFileWatchers(); InitializeControlPanel(); RegisterWristMenuButtons(); } private void EnsureDefaultChatDirectory() { try { Directory.CreateDirectory(Path.Combine(Paths.ConfigPath, "TwitchChatSpawner")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create the default chat-file directory: " + ex.Message)); } } private static void RegisterFilePathConverter() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (!TomlTypeConverter.CanConvert(typeof(FileInfo))) { Type? typeFromHandle = typeof(FileInfo); TypeConverter val = new TypeConverter(); val.ConvertToString = (object value, Type type) => (value != null) ? ((FileInfo)value).FullName : string.Empty; val.ConvertToObject = (string value, Type type) => ConvertToChatFile(value); TomlTypeConverter.AddConverter(typeFromHandle, val); } } private static FileInfo ConvertToChatFile(string value) { string name = ((value != null) ? value.Trim().Trim('"', '\'') : string.Empty); name = Environment.ExpandEnvironmentVariables(name); if (string.IsNullOrEmpty(name) || string.Equals(name, "null", StringComparison.OrdinalIgnoreCase)) { name = "null"; } if (!Path.IsPathRooted(name)) { string text = Paths.ConfigPath; if (string.IsNullOrEmpty(text)) { text = ((!string.IsNullOrEmpty(BasePath)) ? BasePath : Environment.CurrentDirectory); } name = Path.Combine(text, name); } return new FileInfo(Path.GetFullPath(name)); } private bool TryResolveSpawnerPrefab() { if ((Object)(object)prefabToSpawn != (Object)null && (Object)(object)prefabDefinition != (Object)null) { return true; } ChatSpawner[] array = Resources.FindObjectsOfTypeAll<ChatSpawner>(); foreach (ChatSpawner chatSpawner in array) { if (!((Object)(object)chatSpawner == (Object)null) && !((Object)(object)((Component)chatSpawner).gameObject == (Object)null)) { prefabDefinition = chatSpawner; prefabToSpawn = ((Component)chatSpawner).gameObject; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Found spawner prefab " + ((Object)prefabToSpawn).name)); return true; } } string[] array2 = new string[3] { "TwitchChatSpawnerAssets", "TwitchChatSpawner", "JediSpawner" }; for (int j = 0; j < array2.Length; j++) { string text = Path.Combine(BasePath, array2[j]); if (File.Exists(text)) { AssetBundle val = AssetBundle.LoadFromFile(text); if ((Object)(object)val != (Object)null && TryGetSpawnerFromBundle(val)) { return true; } } } ((BaseUnityPlugin)this).Logger.LogWarning((object)"Spawner prefab is not loaded yet. Looked beside the plugin for TwitchChatSpawner and JediSpawner bundles; the next spawn attempt will retry."); return false; } private bool TryGetSpawnerFromBundle(AssetBundle bundle) { string[] array = new string[3] { "Twitch Chat Spawner", "Assets/CompletedBounties/jediSpawner/Twitch Chat Spawner.prefab", "Jedit'sSpawner" }; for (int i = 0; i < array.Length; i++) { GameObject val = bundle.LoadAsset<GameObject>(array[i]); ChatSpawner chatSpawner = ((!((Object)(object)val == (Object)null)) ? val.GetComponent<ChatSpawner>() : null); if (!((Object)(object)chatSpawner == (Object)null)) { prefabToSpawn = val; prefabDefinition = chatSpawner; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded spawner prefab " + ((Object)prefabToSpawn).name + " from bundle " + ((Object)bundle).name)); return true; } } return false; } private void RegisterWristMenuButtons() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown AddWristButton("TCS: Open Armor Panel", new ButtonClickEvent(OnSpawnArmorPanelButton)); } private void AddWristButton(string label, ButtonClickEvent callback) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown WristMenuButton item = new WristMenuButton(label, callback); wristButtons.Add(item); WristMenuAPI.Buttons.Add(item); } private void InitializeControlPanel() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown controlPanel = new LockablePanel(); controlPanel.Configure += ConfigureControlPanel; armorPanel = new LockablePanel(); armorPanel.Configure += ConfigureArmorPanel; } private void ConfigureArmorPanel(GameObject panel) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) Transform val = ((!((Object)(object)panel == (Object)null)) ? panel.transform.Find("OptionsCanvas_0_Main/Canvas") : null); GameObject val2 = ((!((Object)(object)prefabDefinition == (Object)null)) ? prefabDefinition.ArmorPanelPrefab : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Armor panel prefab is missing. Generate it with Tools > Twitch Chat Spawner > Create Armor Panel in MeatKit, then rebuild the bundle."); return; } GameObject val3 = Object.Instantiate<GameObject>(val2, val.position, val.rotation, val.parent); val3.transform.localScale = val.localScale; ArmorSwitchPanel component = val3.GetComponent<ArmorSwitchPanel>(); if ((Object)(object)component == (Object)null || (Object)(object)val3.GetComponent<UniversalModPanel>() == (Object)null) { Object.Destroy((Object)(object)val3); ((BaseUnityPlugin)this).Logger.LogError((object)"Armor panel prefab needs ArmorSwitchPanel and UniversalModPanel components."); return; } component.Bind(this); val3.GetComponent<UniversalModPanel>().Navigate("Armor"); armorPanelUi = component; ((Component)val).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)val).gameObject); RefreshPanelUi(); } private void ConfigureControlPanel(GameObject panel) { panelStatusText = null; panelCountText = null; panelSelectionText = null; panelFriendlyArmorButton = null; panelEnemyTemplateButton = null; panelEnemyArmorButton = null; panelAutoFriendlyButton = null; panelAutoEnemyButton = null; panelAutoBossButton = null; panelProtectionButton = null; Transform val = ((!((Object)(object)panel == (Object)null)) ? panel.transform.Find("OptionsCanvas_0_Main/Canvas") : null); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find the Sodalite lockable-panel canvas."); return; } UiWidget.CreateAndConfigureWidget<GridLayoutWidget>(((Component)val).gameObject, (Action<GridLayoutWidget>)delegate(GridLayoutWidget grid) { //IL_0016: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_0140: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Expected O, but got Unknown //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Expected O, but got Unknown //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Expected O, but got Unknown //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Expected O, but got Unknown ((Transform)((UiWidget)grid).RectTransform).localScale = new Vector3(0.07f, 0.07f, 0.07f); ((Transform)((UiWidget)grid).RectTransform).localPosition = Vector3.zero; ((UiWidget)grid).RectTransform.anchoredPosition = Vector2.zero; ((UiWidget)grid).RectTransform.sizeDelta = new Vector2(528.5714f, 342.85715f); ((UiWidget)grid).RectTransform.pivot = new Vector2(0.5f, 1f); ((Transform)((UiWidget)grid).RectTransform).localRotation = Quaternion.identity; ((LayoutWidget<GridLayoutGroup>)(object)grid).LayoutGroup.cellSize = new Vector2(171f, 50f); ((LayoutWidget<GridLayoutGroup>)(object)grid).LayoutGroup.spacing = Vector2.one * 4f; ((LayoutWidget<GridLayoutGroup>)(object)grid).LayoutGroup.startCorner = (Corner)0; ((LayoutWidget<GridLayoutGroup>)(object)grid).LayoutGroup.startAxis = (Axis)0; ((LayoutGroup)((LayoutWidget<GridLayoutGroup>)(object)grid).LayoutGroup).childAlignment = (TextAnchor)1; ((LayoutWidget<GridLayoutGroup>)(object)grid).LayoutGroup.constraint = (Constraint)1; ((LayoutWidget<GridLayoutGroup>)(object)grid).LayoutGroup.constraintCount = 3; AddPanelText(grid, "TWITCH CHAT\nSPAWNER", 20); panelCountText = AddPanelText(grid, "Alive\nF: 0 E: 0 B: 0", 16); panelStatusText = AddPanelText(grid, panelStatus, 14); AddPanelButton(grid, "SPAWN FRIENDLY", new ButtonClickEvent(OnSpawnFriendlyButton)); AddPanelButton(grid, "SPAWN ENEMY", new ButtonClickEvent(OnSpawnEnemyButton)); AddPanelButton(grid, "SPAWN BOSS", new ButtonClickEvent(OnSpawnBossButton)); panelFriendlyArmorButton = AddPanelButton(grid, "Friendly Armor", new ButtonClickEvent(OnNextFriendlyArmorButton)); panelEnemyTemplateButton = AddPanelButton(grid, "Enemy Type", new ButtonClickEvent(OnNextEnemyTypeButton)); panelEnemyArmorButton = AddPanelButton(grid, "Enemy Armor", new ButtonClickEvent(OnNextEnemyArmorButton)); AddPanelButton(grid, "APPLY FRIENDLY\nARMOR", new ButtonClickEvent(OnApplyFriendlyArmorButton)); AddPanelButton(grid, "REFRESH STEAM\nFRIENDS", new ButtonClickEvent(OnRefreshSteamFriendsButton)); AddPanelButton(grid, "APPLY ENEMY\nARMOR", new ButtonClickEvent(OnApplyEnemyArmorButton)); panelAutoFriendlyButton = AddPanelButton(grid, "Auto Friendly", new ButtonClickEvent(OnToggleAutoFriendlyButton)); panelAutoEnemyButton = AddPanelButton(grid, "Auto Enemy", new ButtonClickEvent(OnToggleAutoEnemyButton)); panelAutoBossButton = AddPanelButton(grid, "Auto Boss", new ButtonClickEvent(OnToggleAutoBossButton)); panelProtectionButton = AddPanelButton(grid, "Streamer Protection", new ButtonClickEvent(OnToggleStreamerProtectionButton)); panelSelectionText = AddPanelText(grid, "Selections", 13); AddPanelText(grid, "Point + trigger\nLock icon pins panel", 13); }); RefreshPanelUi(); } private static TextWidget AddPanelText(GridLayoutWidget grid, string value, int maximumFontSize) { TextWidget result = null; ((LayoutWidget<GridLayoutGroup>)(object)grid).AddChild<TextWidget>((Action<TextWidget>)delegate(TextWidget text) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) result = text; text.Text.text = value; text.Text.alignment = (TextAnchor)4; text.Text.fontSize = maximumFontSize; text.Text.resizeTextForBestFit = true; text.Text.resizeTextMinSize = 9; text.Text.resizeTextMaxSize = maximumFontSize; text.Text.horizontalOverflow = (HorizontalWrapMode)0; text.Text.verticalOverflow = (VerticalWrapMode)0; ((Transform)((UiWidget)text).RectTransform).localRotation = Quaternion.identity; }); return result; } private static ButtonWidget AddPanelButton(GridLayoutWidget grid, string label, ButtonClickEvent callback) { ButtonWidget result = null; ((LayoutWidget<GridLayoutGroup>)(object)grid).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) result = button; button.ButtonText.text = label; button.ButtonText.fontSize = 16; button.ButtonText.resizeTextForBestFit = true; button.ButtonText.resizeTextMinSize = 9; button.ButtonText.resizeTextMaxSize = 16; button.ButtonText.horizontalOverflow = (HorizontalWrapMode)0; button.ButtonText.verticalOverflow = (VerticalWrapMode)0; ((Component)button.ButtonText).transform.localRotation = Quaternion.identity; button.AddButtonListener(callback); }); return result; } private void RefreshPanelUi() { if ((Object)(object)armorPanelUi != (Object)null) { armorPanelUi.Refresh(prefabDefinition, friendlyArmorIndex, enemyTemplateIndex, enemyArmorIndex, panelStatus, randomArmor.Value); } if (!((Object)(object)panelCountText == (Object)null)) { panelCountText.Text.text = "Alive\nF: " + GetLivingCount(spawnedChatters) + " E: " + GetLivingCount(spawnedEnemyChatters) + " B: " + GetLivingCount(spawnedBosses); if ((Object)(object)panelStatusText != (Object)null) { panelStatusText.Text.text = ShortPanelValue(panelStatus, 44); } string value = ((!((Object)(object)prefabDefinition == (Object)null)) ? prefabDefinition.GetFriendlyOutfitName(friendlyArmorIndex) : "Unavailable"); string value2 = ((!((Object)(object)prefabDefinition == (Object)null)) ? prefabDefinition.GetEnemyTemplateName(enemyTemplateIndex) : "Unavailable"); string value3 = ((!((Object)(object)prefabDefinition == (Object)null)) ? prefabDefinition.GetEnemyOutfitName(enemyTemplateIndex, enemyArmorIndex) : "Unavailable"); if ((Object)(object)panelFriendlyArmorButton != (Object)null) { panelFriendlyArmorButton.ButtonText.text = "FRIENDLY ARMOR\n" + ShortPanelValue(value, 20); } if ((Object)(object)panelEnemyTemplateButton != (Object)null) { panelEnemyTemplateButton.ButtonText.text = "ENEMY TYPE\n" + ShortPanelValue(value2, 20); } if ((Object)(object)panelEnemyArmorButton != (Object)null) { panelEnemyArmorButton.ButtonText.text = "ENEMY ARMOR\n" + ShortPanelValue(value3, 20); } if ((Object)(object)panelAutoFriendlyButton != (Object)null) { panelAutoFriendlyButton.ButtonText.text = "AUTO FRIENDLY\n" + OnOff(autoSpawnFriendly.Value); } if ((Object)(object)panelAutoEnemyButton != (Object)null) { panelAutoEnemyButton.ButtonText.text = "AUTO ENEMY\n" + OnOff(autoSpawnEnemy.Value); } if ((Object)(object)panelAutoBossButton != (Object)null) { panelAutoBossButton.ButtonText.text = "AUTO BOSS\n" + OnOff(autoSpawnBoss.Value); } if ((Object)(object)panelProtectionButton != (Object)null) { panelProtectionButton.ButtonText.text = "STREAMER PROTECTION\n" + OnOff(protectStreamer.Value); } if ((Object)(object)panelSelectionText != (Object)null) { panelSelectionText.Text.text = "F: " + ShortPanelValue(value, 15) + "\nE: " + ShortPanelValue(value2, 10) + " / " + ShortPanelValue(value3, 10); } } } private static string OnOff(bool value) { return (!value) ? "OFF" : "ON"; } private static string ShortPanelValue(string value, int maximumLength) { if (string.IsNullOrEmpty(value)) { return "None"; } value = value.Replace("\r", " ").Replace("\n", " ").Trim(); if (value.Length <= maximumLength) { return value; } return value.Substring(0, Mathf.Max(1, maximumLength - 3)) + "..."; } private void OnDestroy() { for (int i = 0; i < wristButtons.Count; i++) { WristMenuAPI.Buttons.Remove(wristButtons[i]); } wristButtons.Clear(); if (controlPanel != null) { controlPanel.Configure -= ConfigureControlPanel; } if (armorPanel != null) { armorPanel.Configure -= ConfigureArmorPanel; } if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } recentFriendlyShots.Clear(); movementStates.Clear(); if ((Object)(object)instance == (Object)(object)this) { instance = null; } } public void Update() { //IL_0007: 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_003d: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(friendlySpawnKey.Value)) { SpawnFriendlyFromCurrentFile(); } if (Input.GetKeyDown(enemySpawnKey.Value)) { SpawnEnemyFromCurrentFile(); } if (Input.GetKeyDown(bossSpawnKey.Value)) { SpawnBossFromCurrentFile(); } if (Time.unscaledTime >= nextFilePoll) { nextFilePoll = Time.unscaledTime + Mathf.Max(0.1f, filePollSeconds.Value); PollChatFiles(); } if (Time.unscaledTime >= nextSosigUpdate) { nextSosigUpdate = Time.unscaledTime + 0.5f; UpdateSpawnedSosigs(); RefreshPanelUi(); } if (protectStreamer.Value && Time.unscaledTime >= nextFriendlyFireCheck) { nextFriendlyFireCheck = Time.unscaledTime + 0.1f; ProtectStreamerFromFriendlyFire(); } } public static void RegisterFriendly(Sosig sosig) { if ((Object)(object)sosig != (Object)null && !spawnedChatters.Contains(sosig)) { spawnedChatters.Add(sosig); } } public static void RegisterEnemy(Sosig sosig) { if ((Object)(object)sosig != (Object)null && !spawnedEnemyChatters.Contains(sosig)) { spawnedEnemyChatters.Add(sosig); } } public static void RegisterBoss(Sosig sosig) { if ((Object)(object)sosig != (Object)null && !spawnedBosses.Contains(sosig)) { spawnedBosses.Add(sosig); } } public void SpawnFriendlyFromCurrentFile() { if (!TryReadChatName(friendlyNameFile.Value, out var chatterName) && !TryGetNextSteamFriendName(out chatterName)) { chatterName = GetRandomFallbackName(FriendlyFallbackNames, "Friendly Chatter"); } SpawnFriendly(chatterName); } public void SpawnEnemyFromCurrentFile() { if (!TryReadChatName(enemyNameFile.Value, out var chatterName) && !TryGetNextSteamFriendName(out chatterName)) { chatterName = GetRandomFallbackName(EnemyFallbackNames, "Enemy Chatter"); } SpawnEnemy(chatterName); } public void SpawnBossFromCurrentFile() { if (!TryReadChatName(bossNameFile.Value, out var chatterName) && !TryReadChatName(enemyNameFile.Value, out chatterName) && !TryGetNextSteamFriendName(out chatterName)) { chatterName = GetRandomFallbackName(BossFallbackNames, "Chat Boss"); } SpawnBoss(ExtractBossName(chatterName)); } public bool SpawnFriendly(string chatterName) { //IL_0067: 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) PruneNullEntries(spawnedChatters); if (!CanSpawn(GetLivingCount(spawnedChatters), "friendly") || !CanUseSpawner()) { return false; } if (!TryGetPlayerSpawnPoint(1.5f, out var spawnPoint)) { return false; } SpawnerName = CleanName(chatterName, "Friendly Chatter"); GameObject val = Object.Instantiate<GameObject>(prefabToSpawn, spawnPoint, Quaternion.identity); ChatSpawner component = val.GetComponent<ChatSpawner>(); Sosig val2 = ((!((Object)(object)component == (Object)null)) ? component.SpawningSequence((!randomArmor.Value) ? friendlyArmorIndex : (-2)) : null); Object.Destroy((Object)(object)val); SetStatus((!((Object)(object)val2 == (Object)null)) ? ("Spawned " + SpawnerName) : "Friendly spawn failed"); return (Object)(object)val2 != (Object)null; } public bool SpawnEnemy(string chatterName) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) PruneNullEntries(spawnedEnemyChatters); if (!CanSpawn(GetLivingCount(spawnedEnemyChatters), "enemy") || !CanUseSpawner()) { return false; } if (!TryGetEnemySpawnPoint(out var spawnPoint, out var iff)) { return false; } SpawnerName = CleanName(chatterName, "Enemy Chatter"); GameObject val = Object.Instantiate<GameObject>(prefabToSpawn, spawnPoint, Quaternion.identity); ChatSpawner component = val.GetComponent<ChatSpawner>(); Sosig val2 = ((!((Object)(object)component == (Object)null)) ? component.SpawningSequenceEnemy(iff, enemyTemplateIndex, (!randomArmor.Value) ? enemyArmorIndex : (-2)) : null); Object.Destroy((Object)(object)val); SetStatus((!((Object)(object)val2 == (Object)null)) ? ("Spawned enemy " + SpawnerName) : "Enemy spawn failed"); return (Object)(object)val2 != (Object)null; } public bool SpawnBoss(string chatterName) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) PruneNullEntries(spawnedBosses); int num = Mathf.Max(1, maxActiveBosses.Value); if (GetLivingCount(spawnedBosses) >= num) { SetStatus("A chat boss is already alive"); return false; } if (!CanUseSpawner()) { return false; } int iff; Vector3 spawnPoint; if ((Object)(object)GM.TNH_Manager == (Object)null) { iff = fallbackEnemyIFF.Value; if (!TryGetPlayerSpawnPoint(8f, out spawnPoint)) { return false; } } else if (!TryGetEnemySpawnPoint(out spawnPoint, out iff)) { return false; } string text = CleanName(chatterName, "Chat Boss"); SpawnerName = "BOSS: " + text; GameObject val = Object.Instantiate<GameObject>(prefabToSpawn, spawnPoint, Quaternion.identity); ChatSpawner component = val.GetComponent<ChatSpawner>(); Sosig val2 = ((!((Object)(object)component == (Object)null)) ? component.SpawningSequenceBoss(iff, enemyTemplateIndex, (!randomArmor.Value) ? enemyArmorIndex : (-2), bossHealthMultiplier.Value, bossScaleMultiplier.Value, bossSpeedMultiplier.Value) : null); Object.Destroy((Object)(object)val); previousLivingBossCount = GetLivingCount(spawnedBosses); SetStatus((!((Object)(object)val2 == (Object)null)) ? (text + " became the boss") : "Boss spawn failed"); return (Object)(object)val2 != (Object)null; } public void CycleFriendlyArmor() { StepFriendlyArmor(1); } public void StepFriendlyArmor(int direction) { if (!((Object)(object)prefabDefinition == (Object)null)) { int friendlyOutfitCount = prefabDefinition.GetFriendlyOutfitCount(); if (friendlyOutfitCount == 0) { SetStatus("No friendly armor profiles are configured"); return; } friendlyArmorIndex = WrapIndex(friendlyArmorIndex + direction, friendlyOutfitCount); SetStatus("Friendly armor: " + prefabDefinition.GetFriendlyOutfitName(friendlyArmorIndex)); } } public void CycleEnemyTemplate() { StepEnemyTemplate(1); } public void StepEnemyTemplate(int direction) { if (!((Object)(object)prefabDefinition == (Object)null)) { int enemyTemplateCount = prefabDefinition.GetEnemyTemplateCount(); if (enemyTemplateCount == 0) { SetStatus("No enemy types are configured"); return; } enemyTemplateIndex = WrapIndex(enemyTemplateIndex + direction, enemyTemplateCount); enemyArmorIndex = 0; SetStatus("Enemy type: " + prefabDefinition.GetEnemyTemplateName(enemyTemplateIndex) + "; armor: " + prefabDefinition.GetEnemyOutfitName(enemyTemplateIndex, enemyArmorIndex)); } } public void CycleEnemyArmor() { StepEnemyArmor(1); } public void StepEnemyArmor(int direction) { if (!((Object)(object)prefabDefinition == (Object)null)) { int enemyOutfitCount = prefabDefinition.GetEnemyOutfitCount(enemyTemplateIndex); if (enemyOutfitCount == 0) { SetStatus("No armor profiles are configured for the selected enemy type"); return; } enemyArmorIndex = WrapIndex(enemyArmorIndex + direction, enemyOutfitCount); SetStatus("Enemy armor: " + prefabDefinition.GetEnemyOutfitName(enemyTemplateIndex, enemyArmorIndex)); } } public void ApplyFriendlyArmorToAll() { if (!((Object)(object)prefabDefinition == (Object)null) && !((Object)(object)prefabDefinition.t == (Object)null)) { SosigOutfitConfig outfit = prefabDefinition.GetOutfit(prefabDefinition.t, friendlyArmorIndex); int num = ApplyOutfitToList(spawnedChatters, outfit); SetStatus("Changed armor on " + num + " friendlies"); } } public void ToggleRandomArmor() { randomArmor.Value = !randomArmor.Value; SetStatus("Random T&H armor: " + ((!randomArmor.Value) ? "OFF (use selected outfits)" : "ON (one outfit per Sosig)")); } public void ApplyEnemyArmorToAll() { if (!((Object)(object)prefabDefinition == (Object)null)) { SosigEnemyTemplate enemyTemplate = prefabDefinition.GetEnemyTemplate(enemyTemplateIndex); SosigOutfitConfig outfit = prefabDefinition.GetOutfit(enemyTemplate, enemyArmorIndex); int num = ApplyOutfitToList(spawnedEnemyChatters, outfit); SetStatus("Changed armor on " + num + " enemies"); } } private int ApplyOutfitToList(List<Sosig> sosigs, SosigOutfitConfig outfit) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 if ((Object)(object)prefabDefinition == (Object)null || (!randomArmor.Value && (Object)(object)outfit == (Object)null)) { return 0; } List<SosigOutfitConfig> list = ((!randomArmor.Value) ? null : prefabDefinition.GetAvailableArmorOutfits()); if (randomArmor.Value && list.Count == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Runtime armor catalog is unavailable. Current armor was retained."); return 0; } PruneNullEntries(sosigs); int num = 0; for (int i = 0; i < sosigs.Count; i++) { Sosig val = sosigs[i]; if (!((Object)(object)val == (Object)null) && (int)val.BodyState != 3) { SosigOutfitConfig outfit2 = ((!randomArmor.Value) ? outfit : prefabDefinition.PickRandomArmor(list)); if (prefabDefinition.ApplyOutfit(val, outfit2, removeCurrentArmor: true)) { num++; } } } return num; } private void PollChatFiles() { if (autoSpawnFriendly.Value && HasFileChanged(friendlyNameFile.Value, ref friendlyWriteTicks)) { SpawnFriendlyFromCurrentFile(); } if (autoSpawnEnemy.Value && HasFileChanged(enemyNameFile.Value, ref enemyWriteTicks) && TryReadChatName(enemyNameFile.Value, out var chatterName)) { if (IsBossCommand(chatterName)) { SpawnBoss(ExtractBossName(chatterName)); } else { SpawnEnemy(chatterName); } } if (autoSpawnBoss.Value && HasFileChanged(bossNameFile.Value, ref bossWriteTicks)) { SpawnBossFromCurrentFile(); } } private void SeedFileWatchers() { friendlyWriteTicks = GetWriteTicks(friendlyNameFile.Value); enemyWriteTicks = GetWriteTicks(enemyNameFile.Value); bossWriteTicks = GetWriteTicks(bossNameFile.Value); } private static bool HasFileChanged(FileInfo file, ref long previousTicks) { long writeTicks = GetWriteTicks(file); if (writeTicks == 0) { return false; } if (previousTicks == 0) { previousTicks = writeTicks; return false; } if (writeTicks <= previousTicks) { return false; } previousTicks = writeTicks; return true; } private static long GetWriteTicks(FileInfo file) { try { return (!IsUsablePath(file) || !File.Exists(file.FullName)) ? 0 : File.GetLastWriteTimeUtc(file.FullName).Ticks; } catch { return 0L; } } private static bool TryReadChatName(FileInfo file, out string chatterName) { chatterName = string.Empty; if (!IsUsablePath(file) || !File.Exists(file.FullName)) { return false; } try { string contents; using (FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { using StreamReader streamReader = new StreamReader(stream, detectEncodingFromByteOrderMarks: true); contents = streamReader.ReadToEnd(); } return TryExtractChatName(contents, out chatterName); } catch { return false; } } private static bool TryExtractChatName(string contents, out string chatterName) { chatterName = string.Empty; if (string.IsNullOrEmpty(contents)) { return false; } contents = contents.Trim().TrimStart(new char[1] { '\ufeff' }); if (contents.Length == 0) { return false; } Match match = Regex.Match(contents, "\"(?:name|user_?name|viewer|chatter|display_?name)\"\\s*:\\s*\"((?:\\\\.|[^\"])*)\"", RegexOptions.IgnoreCase); if (match.Success) { return TryCleanChatName(match.Groups[1].Value, out chatterName); } if (contents.Length >= 2 && contents[0] == '"' && contents[contents.Length - 1] == '"') { return TryCleanChatName(contents.Substring(1, contents.Length - 2), out chatterName); } string[] array = contents.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text[0] == ';' || text[0] == '#' || (text[0] == '[' && text[text.Length - 1] == ']')) { continue; } int num = text.IndexOf('='); if (num > 0) { string key = text.Substring(0, num).Trim().Replace("_", string.Empty) .Replace("-", string.Empty) .Replace(" ", string.Empty); if (IsChatNameKey(key)) { return TryCleanChatName(text.Substring(num + 1), out chatterName); } } } for (int j = 0; j < array.Length; j++) { string text2 = array[j].Trim(); if (text2.Length != 0 && text2[0] != ';' && text2[0] != '#' && text2[0] != '[' && text2.IndexOf('=') < 0) { return TryCleanChatName(text2, out chatterName); } } return false; } private static bool IsChatNameKey(string key) { return string.Equals(key, "name", StringComparison.OrdinalIgnoreCase) || string.Equals(key, "username", StringComparison.OrdinalIgnoreCase) || string.Equals(key, "viewer", StringComparison.OrdinalIgnoreCase) || string.Equals(key, "viewername", StringComparison.OrdinalIgnoreCase) || string.Equals(key, "chatter", StringComparison.OrdinalIgnoreCase) || string.Equals(key, "displayname", StringComparison.OrdinalIgnoreCase) || string.Equals(key, "twitchname", StringComparison.OrdinalIgnoreCase) || string.Equals(key, "user", StringComparison.OrdinalIgnoreCase); } private static bool TryCleanChatName(string value, out string chatterName) { chatterName = ((value != null) ? value.Trim().Trim('"', '\'') : string.Empty); chatterName = chatterName.Replace("\\\"", "\"").Replace("\\n", " ").Replace("\\r", " ") .Trim(); if (chatterName.Length > 64) { chatterName = chatterName.Substring(0, 64); } if (chatterName.Length == 0 || string.Equals(chatterName, "undefined", StringComparison.OrdinalIgnoreCase) || string.Equals(chatterName, "null", StringComparison.OrdinalIgnoreCase) || string.Equals(chatterName, "none", StringComparison.OrdinalIgnoreCase)) { chatterName = string.Empty; return false; } return true; } private static bool IsUsablePath(FileInfo file) { return file != null && !string.IsNullOrEmpty(file.FullName) && !string.Equals(file.Name, "null", StringComparison.OrdinalIgnoreCase); } private bool TryGetPlayerSpawnPoint(float distance, out Vector3 spawnPoint) { //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_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_005e: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_0102: 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) //IL_0107: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) spawnPoint = Vector3.zero; if ((Object)(object)GM.CurrentPlayerBody == (Object)null || (Object)(object)GM.CurrentPlayerBody.Head == (Object)null) { SetStatus("Player body is not ready"); return false; } Vector3 position = ((Component)GM.CurrentPlayerBody).transform.position; Vector3 forward = GM.CurrentPlayerBody.Head.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.01f) { forward = ((Component)GM.CurrentPlayerBody).transform.forward; } ((Vector3)(ref forward)).Normalize(); float[] array = new float[8] { 0f, 45f, -45f, 90f, -90f, 135f, -135f, 180f }; float[] array2 = new float[3] { 0f, 1.5f, 3f }; for (int i = 0; i < array2.Length; i++) { float num = Mathf.Max(1.5f, distance + array2[i]); for (int j = 0; j < array.Length; j++) { Vector3 val = Quaternion.Euler(0f, array[j], 0f) * forward; Vector3 candidate = position + val * num; if (TryGetWalkableClearPoint(candidate, out spawnPoint)) { return true; } } } SetStatus("Could not find clear walkable space near the player"); return false; } private static bool TryGetWalkableClearPoint(Vector3 candidate, out Vector3 spawnPoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_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_0038: 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_0042: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(candidate, ref val, 4f, -1) && IsSpawnCapsuleClear(((NavMeshHit)(ref val)).position)) { spawnPoint = ((NavMeshHit)(ref val)).position + Vector3.up * 0.05f; return true; } spawnPoint = Vector3.zero; return false; } private static bool IsSpawnCapsuleClear(Vector3 floorPoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_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_0018: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0034: Unknown result type (might be due to invalid IL or missing references) Vector3 val = floorPoint + Vector3.up * 0.45f; Vector3 val2 = floorPoint + Vector3.up * 1.65f; return !Physics.CheckCapsule(val, val2, 0.35f, LayerMask.op_Implicit(environmentMask)); } private bool TryGetEnemySpawnPoint(out Vector3 spawnPoint, out int iff) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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_010b: Unknown result type (might be due to invalid IL or missing references) iff = fallbackEnemyIFF.Value; if ((Object)(object)GM.TNH_Manager != (Object)null) { TNHManager = GM.TNH_Manager; } if ((Object)(object)TNHManager != (Object)null && (Object)(object)TNHManager.m_curHoldPoint != (Object)null) { if ((int)TNHManager.Phase == 1 && TNHManager.m_curHoldPoint.AttackVectors != null && TNHManager.m_curHoldPoint.AttackVectors.Count > 0) { int index = Random.Range(0, TNHManager.m_curHoldPoint.AttackVectors.Count); AttackVector val = TNHManager.m_curHoldPoint.AttackVectors[index]; if (val != null && val.SpawnPoints_Sosigs_Attack != null && val.SpawnPoints_Sosigs_Attack.Count > 0) { spawnPoint = val.SpawnPoints_Sosigs_Attack[Random.Range(0, val.SpawnPoints_Sosigs_Attack.Count)].position; iff = TNHManager.m_curHoldPoint.m_curPhase.IFFUsed; return true; } } if ((int)TNHManager.Phase == 0 && TNHManager.m_curHoldPoint.SpawnPoints_Turrets.Count > 0) { spawnPoint = ((Component)TNHManager.m_curHoldPoint.SpawnPoints_Turrets[0]).transform.position; if (TNHManager.m_curLevel != null && TNHManager.m_curLevel.PatrolChallenge.Patrols.Count > 0) { iff = TNHManager.m_curLevel.PatrolChallenge.Patrols[0].IFFUsed; } else { iff = TNHManager.m_curHoldPoint.m_curPhase.IFFUsed; } return true; } } return TryGetPlayerSpawnPoint(4f, out spawnPoint); } private bool CanUseSpawner() { if (TryResolveSpawnerPrefab()) { return true; } SetStatus("Spawner prefab is not loaded; check the BepInEx log for the bundle paths that were tried"); return false; } private bool CanSpawn(int livingCount, string teamName) { int num = Mathf.Max(0, maxLivingPerTeam.Value); if (num == 0 || livingCount < num) { return true; } SetStatus("Maximum " + teamName + " chatter count reached"); return false; } private void UpdateSpawnedSosigs() { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Invalid comparison between Unknown and I4 //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Invalid comparison between Unknown and I4 //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Invalid comparison between Unknown and I4 //IL_00e4: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Invalid comparison between Unknown and I4 //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Invalid comparison between Unknown and I4 //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Invalid comparison between Unknown and I4 //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Invalid comparison between Unknown and I4 //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Invalid comparison between Unknown and I4 //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Invalid comparison between Unknown and I4 //IL_023a: Unknown result type (might be due to invalid IL or missing references) PruneNullEntries(spawnedChatters); PruneNullEntries(spawnedEnemyChatters); PruneNullEntries(spawnedBosses); int livingCount = GetLivingCount(spawnedBosses); if (previousLivingBossCount > 0 && livingCount == 0) { SetStatus("The streamer defeated the chat boss"); } previousLivingBossCount = livingCount; if ((Object)(object)GM.CurrentPlayerBody == (Object)null || (Object)(object)GM.CurrentPlayerBody.Head == (Object)null) { return; } for (int i = 0; i < spawnedChatters.Count; i++) { Sosig val = spawnedChatters[i]; if ((int)val.BodyState == 3) { val.TickDownToClear(3f); continue; } bool flag = (int)val.CurrentOrder == 0 || (int)val.CurrentOrder == 9 || (int)val.CurrentOrder == 1 || (int)val.CurrentOrder == 4; bool flag2 = Vector3.Distance(GM.CurrentPlayerBody.Head.position, val.m_assaultPoint) > 4f; if (!val.m_isStunned && (flag || flag2)) { Vector3 followPoint = GetFollowPoint(); if (TryGetReachableWalkablePoint(((Component)val).transform.position, followPoint, out var destination)) { val.CommandAssaultPoint(destination); val.SetCurrentOrder((SosigOrder)7); } } if (val.Priority.HasFreshTarget() && (int)val.CurrentOrder == 3 && val.m_entityRecognition >= 0.65f) { val.SetCurrentOrder((SosigOrder)2); } RecoverStuckSosig(val, isFriendly: true); } for (int j = 0; j < spawnedEnemyChatters.Count; j++) { Sosig val2 = spawnedEnemyChatters[j]; if ((int)val2.BodyState == 3) { val2.TickDownToClear(3f); continue; } if (!val2.m_isStunned && val2.Links != null && val2.Links.Count > 1 && Vector3.Distance(GM.CurrentPlayerBody.Head.position, ((Component)val2.Links[1]).transform.position) > 20f) { CommandSosigToReachablePoint(val2, ((Component)GM.CurrentPlayerBody).transform.position); } if (val2.Priority.HasFreshTarget() && (int)val2.CurrentOrder == 3 && val2.m_entityRecognition >= 0.55f) { val2.SetCurrentOrder((SosigOrder)2); } if ((int)val2.CurrentOrder == 0 || (int)val2.CurrentOrder == 9 || (int)val2.CurrentOrder == 1) { CommandSosigToReachablePoint(val2, ((Component)GM.CurrentPlayerBody).transform.position); } RecoverStuckSosig(val2, isFriendly: false); } PruneMovementStates(); } private static bool TryGetReachableWalkablePoint(Vector3 from, Vector3 desired, out Vector3 destination) { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0041: 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_005a: 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_0073: Unknown result type (might be due to invalid IL or missing references) destination = Vector3.zero; NavMeshHit val = default(NavMeshHit); NavMeshHit val2 = default(NavMeshHit); if (!NavMesh.SamplePosition(from, ref val, 2.5f, -1) || !NavMesh.SamplePosition(desired, ref val2, 3f, -1)) { return false; } NavMeshPath val3 = new NavMeshPath(); if (!NavMesh.CalculatePath(((NavMeshHit)(ref val)).position, ((NavMeshHit)(ref val2)).position, -1, val3) || (int)val3.status != 0) { return false; } destination = ((NavMeshHit)(ref val2)).position; return true; } private static bool CommandSosigToReachablePoint(Sosig sosig, Vector3 desired) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sosig == (Object)null) { return false; } if (!TryGetReachableWalkablePoint(((Component)sosig).transform.position, desired, out var destination)) { return false; } sosig.CommandAssaultPoint(destination); sosig.SetCurrentOrder((SosigOrder)7); return true; } private void RecoverStuckSosig(Sosig sosig, bool isFriendly) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //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_0126: 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) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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_0188: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: 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) //IL_01b2: 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) if ((Object)(object)sosig == (Object)null || sosig.m_isStunned || (int)sosig.BodyState == 3) { return; } if (!movementStates.TryGetValue(sosig, out var value)) { movementStates[sosig] = new SosigMovementState(((Component)sosig).transform.position, Time.unscaledTime); return; } if (Vector3.Distance(value.LastPosition, ((Component)sosig).transform.position) >= 0.3f) { value.LastPosition = ((Component)sosig).transform.position; value.LastMovementTime = Time.unscaledTime; return; } Vector3 position = ((Component)GM.CurrentPlayerBody).transform.position; float num = Vector3.Distance(((Component)sosig).transform.position, position); float num2 = ((!isFriendly) ? 3f : 4f); if (num <= num2 || Time.unscaledTime - value.LastMovementTime < 3f) { return; } Vector3 desired = ((!isFriendly) ? position : GetFollowPoint()); if (!CommandSosigToReachablePoint(sosig, desired)) { Vector3 val = ((Component)sosig).transform.position - position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = GM.CurrentPlayerBody.Head.forward; } ((Vector3)(ref val)).Normalize(); float num3 = ((!(Random.value < 0.5f)) ? 1f : (-1f)); desired = position + Quaternion.Euler(0f, 55f * num3, 0f) * val * num2; CommandSosigToReachablePoint(sosig, desired); } value.LastPosition = ((Component)sosig).transform.position; value.LastMovementTime = Time.unscaledTime; } private void PruneMovementStates() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 List<Sosig> list = null; foreach (KeyValuePair<Sosig, SosigMovementState> movementState in movementStates) { if (!((Object)(object)movementState.Key != (Object)null) || (int)movementState.Key.BodyState == 3) { if (list == null) { list = new List<Sosig>(); } list.Add(movementState.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { movementStates.Remove(list[i]); } } } private void ProtectStreamerFromFriendlyFire() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Invalid comparison between Unknown and I4 //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)GM.CurrentPlayerBody == (Object)null || (Object)(object)GM.CurrentPlayerBody.Head == (Object)null) { return; } PruneNullEntries(spawnedChatters); Vector3 playerPoint = GM.CurrentPlayerBody.Head.position - Vector3.up * 0.25f; float radius = Mathf.Clamp(streamerSafetyRadius.Value, 0.25f, 2f); for (int i = 0; i < spawnedChatters.Count; i++) { Sosig val = spawnedChatters[i]; if ((Object)(object)val == (Object)null || (int)val.BodyState == 3) { continue; } int playerIFF = GM.CurrentPlayerBody.GetPlayerIFF(); if (val.GetIFF() != playerIFF) { val.SetIFF(playerIFF); val.SetOriginalIFFTeam(playerIFF); if ((Object)(object)val.E != (Object)null) { val.E.IFFCode = playerIFF; } } val.DoesAggroOnFriendlyFire = false; if (!IsPlayerInFriendlyFiringLane(val, playerPoint, radius)) { blockedFriendlySince.Remove(val); continue; } DelayHeldGuns(val, playerIFF); if (!blockedFriendlySince.TryGetValue(val, out var value)) { blockedFriendlySince[val] = Time.unscaledTime; } else if (Time.unscaledTime - value > 1f) { val.CommandAssaultPoint(GetSafeRepositionPoint(val)); blockedFriendlySince[val] = Time.unscaledTime; } } } private static bool IsPlayerInFriendlyFiringLane(Sosig friendly, Vector3 playerPoint, float radius) { //IL_0050: 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_006f: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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_0109: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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) if (friendly.Hands == null) { return false; } for (int i = 0; i < friendly.Hands.Count; i++) { SosigHand val = friendly.Hands[i]; if (val == null || !val.IsHoldingObject || (Object)(object)val.HeldObject == (Object)null || (int)val.HeldObject.Type != 0) { continue; } Vector3 position = ((Component)val.HeldObject).transform.position; Vector3 val2 = friendly.m_aimPoint - position; if (((Vector3)(ref val2)).sqrMagnitude < 1f) { val2 = ((Component)val.HeldObject).transform.forward * 30f; } float magnitude = ((Vector3)(ref val2)).magnitude; if (magnitude < 0.1f) { continue; } Vector3 val3 = val2 / magnitude; Vector3 val4 = playerPoint - position; float num = Vector3.Dot(val4, val3); if (!(num <= 0.05f) && !(num > magnitude + 1f)) { Vector3 val5 = position + val3 * n