using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using FistVR; using HarmonyLib; using Microsoft.CodeAnalysis; using Steamworks; using UnityEngine; using UnityEngine.UI; using Valve.VR; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace H3TVR { public class AirdropManager : MonoBehaviour { [CompilerGenerated] private sealed class <>c__DisplayClass7_0 { public GameObject crateGO; internal bool b__0() { //IL_0019: 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) return (Object)(object)crateGO == (Object)null || crateGO.transform.position.y < ((Component)GM.CurrentPlayerBody).transform.position.y + 2f; } } [CompilerGenerated] private sealed class d__7 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AirdropManager <>4__this; private <>c__DisplayClass7_0 <>8__1; private Vector3 5__2; private FVRObject 5__3; private Rigidbody 5__4; private bool 5__5; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; 5__3 = null; 5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_0067: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass7_0(); if ((Object)(object)GM.CurrentPlayerBody == (Object)null) { ManualLogSource logger2 = <>4__this.logger; if (logger2 != null) { logger2.LogError((object)"Cannot start airdrop: Player body not found."); } return false; } 5__2 = ((Component)GM.CurrentPlayerBody).transform.position + Vector3.up * 40f; if (!IM.OD.ContainsKey("Crate_Wood_1")) { ManualLogSource logger3 = <>4__this.logger; if (logger3 != null) { logger3.LogError((object)"Cannot start airdrop: Crate template 'Crate_Wood_1' not found."); } return false; } 5__3 = IM.OD["Crate_Wood_1"]; <>8__1.crateGO = Object.Instantiate(((AnvilAsset)5__3).GetGameObject(), 5__2, Quaternion.identity); 5__4 = <>8__1.crateGO.GetComponent(); if ((Object)(object)5__4 == (Object)null) { ManualLogSource logger4 = <>4__this.logger; if (logger4 != null) { logger4.LogError((object)"Airdrop crate has no Rigidbody!"); } Object.Destroy((Object)(object)<>8__1.crateGO); return false; } 5__4.drag = 0.2f; 5__5 = Random.value < 0.7f; <>2__current = (object)new WaitUntil((Func)(() => (Object)(object)<>8__1.crateGO == (Object)null || <>8__1.crateGO.transform.position.y < ((Component)GM.CurrentPlayerBody).transform.position.y + 2f)); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)<>8__1.crateGO != (Object)null) { <>4__this.PopulateCrate(<>8__1.crateGO.transform.position, 5__5); <>8__1.crateGO.SendMessage("Damage", (object)1000f, (SendMessageOptions)1); ManualLogSource logger = <>4__this.logger; if (logger != null) { logger.LogInfo((object)"Airdrop has landed!"); } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private H3TVRImproved plugin; private ManualLogSource logger; private const string CrateId = "Crate_Wood_1"; private const float SpawnHeight = 40f; private const float ParachuteSlowdown = 0.2f; public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource) { plugin = pluginInstance; logger = logSource; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Airdrop Manager initialized."); } } public void CallAirdrop(string username) { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Airdrop called in by " + username + "!")); } ((MonoBehaviour)this).StartCoroutine(AirdropSequence()); } private IEnumerator AirdropSequence() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__7(0) { <>4__this = this }; } private void PopulateCrate(Vector3 position, bool isHelpful) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (isHelpful) { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Airdrop is... HELPFUL!"); } SpawnRandomHelpfulItem(position); SpawnItem("Health_Sausage", position + Vector3.up * 0.1f); } else { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)"Airdrop is... a TROLL!"); } SpawnItem("PinnedGrenadeM67", position); } } private void SpawnRandomHelpfulItem(Vector3 position) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[3] { "MeatBatBaseball", "Health_Sausage", "SuppressorBottle" }; string itemId = array[Random.Range(0, array.Length)]; SpawnItem(itemId, position); } private void SpawnItem(string itemId, Vector3 position) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) try { if (IM.OD.ContainsKey(itemId)) { FVRObject val = IM.OD[itemId]; Object.Instantiate(((AnvilAsset)val).GetGameObject(), position, Quaternion.identity); return; } ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Item '" + itemId + "' not found in ObjectDictionary")); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to spawn item '" + itemId + "': " + ex.Message)); } } } } public class SosigBehaviorController { private ManualLogSource logger; private static readonly LayerMask EnvironmentMask = LayerMask.op_Implicit(LayerMask.GetMask(new string[1] { "Environment" })); public float AllyFollowDistance { get; set; } = 5f; public float AllyMinDistance { get; set; } = 2f; public float AllyCombatRange { get; set; } = 15f; public float AllyDefendRadius { get; set; } = 10f; public bool AllyProtectPlayer { get; set; } = true; public bool AllyHoldFire { get; set; } = false; public void Initialize(ManualLogSource logSource) { logger = logSource; } public void SetupAllyBehavior(Sosig sosig) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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) try { FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody; object obj; if (currentPlayerBody == null) { obj = null; } else { Transform head = currentPlayerBody.Head; obj = ((head != null) ? ((Component)head).transform : null); } if ((Object)obj == (Object)null) { return; } sosig.E.IFFCode = 0; sosig.SetIFF(0); if (sosig.Priority.IFFChart != null) { for (int i = 0; i < sosig.Priority.IFFChart.Length; i++) { sosig.Priority.IFFChart[i] = i != 0; } } Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.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); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x + num, position.y, position.z + num2); sosig.CommandAssaultPoint(val); sosig.FallbackOrder = (SosigOrder)4; ConfigureAllyFireSafety(sosig); ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)"Ally sosig configured with IFF 0 (player-friendly)"); } } catch (Exception ex) { ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogError((object)("Ally behavior setup failed: " + ex.Message)); } } } private void ConfigureAllyFireSafety(Sosig sosig) { try { sosig.Mustard = 1f; } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Fire safety config warning: " + ex.Message)); } } } public void SetupEnemyBehavior(Sosig sosig) { //IL_0088: 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) try { FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody; if ((Object)(object)((currentPlayerBody != null) ? ((Component)currentPlayerBody).transform : null) == (Object)null) { return; } int num = 1; sosig.E.IFFCode = num; sosig.SetIFF(num); if (sosig.Priority.IFFChart != null) { for (int i = 0; i < sosig.Priority.IFFChart.Length; i++) { sosig.Priority.IFFChart[i] = i == 0; } } sosig.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position); sosig.FallbackOrder = (SosigOrder)4; } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Enemy behavior setup failed: " + ex.Message)); } } } public void UpdateAllyBehavior(Sosig sosig, float followDistance) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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) //IL_015d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)GM.CurrentPlayerBody?.Head == (Object)null) { return; } try { if (sosig.E.IFFCode != 0) { sosig.E.IFFCode = 0; sosig.SetIFF(0); } if (!sosig.m_isStunned) { Vector3 position = GM.CurrentPlayerBody.Head.position; float num = Vector3.Distance(position, ((Component)sosig).transform.position); float num2 = Vector3.Distance(position, sosig.m_assaultPoint); if (CheckForNearbyEnemies(sosig, AllyCombatRange) && AllyProtectPlayer) { if ((int)sosig.CurrentOrder != 2) { sosig.SetCurrentOrder((SosigOrder)2); } } else if (num2 > followDistance) { float num3 = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f); float num4 = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x + num3, position.y, position.z + num4); if (!Physics.Linecast(position, val, LayerMask.op_Implicit(EnvironmentMask))) { sosig.CommandAssaultPoint(val); } } else if (num < AllyMinDistance) { Vector3 val2 = ((Component)sosig).transform.position - position; Vector3 normalized = ((Vector3)(ref val2)).normalized; Vector3 val3 = ((Component)sosig).transform.position + normalized * 2f; sosig.CommandAssaultPoint(val3); } } if (sosig.Priority.HasFreshTarget() && (int)sosig.CurrentOrder == 3 && sosig.m_entityRecognition >= 0.65f && IsValidEnemyTarget(sosig)) { sosig.SetCurrentOrder((SosigOrder)2); } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Ally update warning: " + ex.Message)); } } } private bool CheckForNearbyEnemies(Sosig allySosig, float range) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) try { if (allySosig.Priority.HasFreshTarget()) { return true; } Sosig[] array = Object.FindObjectsOfType(); Sosig[] array2 = array; foreach (Sosig val in array2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)allySosig) && (int)val.BodyState != 3 && val.E.IFFCode != 0) { float num = Vector3.Distance(((Component)allySosig).transform.position, ((Component)val).transform.position); if (num <= range) { return true; } } } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Enemy check warning: " + ex.Message)); } } return false; } private bool IsValidEnemyTarget(Sosig sosig) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) try { FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody; if ((Object)(object)((currentPlayerBody != null) ? ((Component)currentPlayerBody).transform : null) == (Object)null) { return false; } Vector3 position = ((Component)GM.CurrentPlayerBody).transform.position; Vector3 position2 = ((Component)sosig).transform.position; if (sosig.Priority.HasFreshTarget()) { return true; } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Target validation warning: " + ex.Message)); } } return false; } public void UpdateEnemyBehavior(Sosig sosig, float aggressionDistance) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Invalid comparison between Unknown and I4 //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Invalid comparison between Unknown and I4 //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Invalid comparison between Unknown and I4 //IL_00e8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)GM.CurrentPlayerBody?.Head == (Object)null) { return; } if (!sosig.m_isStunned) { Vector3 position = GM.CurrentPlayerBody.Head.position; float num = Vector3.Distance(position, ((Component)sosig.Links[1]).transform.position); if (num > aggressionDistance) { sosig.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position); } } if (sosig.Priority.HasFreshTarget() && (int)sosig.CurrentOrder == 3 && sosig.m_entityRecognition >= 0.55f) { sosig.SetCurrentOrder((SosigOrder)2); } if ((int)sosig.CurrentOrder == 0 || (int)sosig.CurrentOrder == 9 || (int)sosig.CurrentOrder == 1) { sosig.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position); } } public void SetAlliesHoldFire(bool holdFire) { AllyHoldFire = holdFire; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"Allies hold fire: {holdFire}"); } } public void CommandAlliesDefendPoint(Vector3 point) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) try { foreach (Sosig spawnedChatter in AdvancedChatSosigSpawner.spawnedChatters) { if ((Object)(object)spawnedChatter != (Object)null && (int)spawnedChatter.BodyState != 3) { spawnedChatter.CommandAssaultPoint(point); spawnedChatter.SetCurrentOrder((SosigOrder)1); } } ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"Allies commanded to defend point: {point}"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Defend point command failed: " + ex.Message)); } } } public void CommandAlliesFollowPlayer() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_008c: 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: 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_00b4: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)GM.CurrentPlayerBody?.Head == (Object)null) { return; } Vector3 position = GM.CurrentPlayerBody.Head.position; Vector3 val = default(Vector3); foreach (Sosig spawnedChatter in AdvancedChatSosigSpawner.spawnedChatters) { if ((Object)(object)spawnedChatter != (Object)null && (int)spawnedChatter.BodyState != 3) { float num = Random.Range(-2f, 2f); float num2 = Random.Range(-2f, 2f); ((Vector3)(ref val))..ctor(position.x + num, position.y, position.z + num2); spawnedChatter.CommandAssaultPoint(val); spawnedChatter.FallbackOrder = (SosigOrder)4; } } ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Allies commanded to follow player"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Follow command failed: " + ex.Message)); } } } public void CommandAlliesAttackTarget(Vector3 targetPosition) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) try { foreach (Sosig spawnedChatter in AdvancedChatSosigSpawner.spawnedChatters) { if ((Object)(object)spawnedChatter != (Object)null && (int)spawnedChatter.BodyState != 3) { spawnedChatter.CommandAssaultPoint(targetPosition); spawnedChatter.SetCurrentOrder((SosigOrder)7); } } ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"Allies commanded to attack: {targetPosition}"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Attack command failed: " + ex.Message)); } } } } public class SosigNameManager { private List allyNames = new List(); private List enemyNames = new List(); private ManualLogSource logger; public void Initialize(ManualLogSource logSource) { logger = logSource; } public void LoadNameLists(string allyPath, string enemyPath) { try { if (File.Exists(allyPath)) { string[] array = File.ReadAllLines(allyPath); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (!string.IsNullOrEmpty(text2) && !text2.StartsWith("#") && !text2.StartsWith(";")) { allyNames.Add(text2); } } ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"Loaded {allyNames.Count} ally names"); } } else { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogWarning((object)("Ally names file not found: " + allyPath)); } CreateDefaultNameFile(allyPath, isAlly: true); } if (File.Exists(enemyPath)) { string[] array3 = File.ReadAllLines(enemyPath); string[] array4 = array3; foreach (string text3 in array4) { string text4 = text3.Trim(); if (!string.IsNullOrEmpty(text4) && !text4.StartsWith("#") && !text4.StartsWith(";")) { enemyNames.Add(text4); } } ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogInfo((object)$"Loaded {enemyNames.Count} enemy names"); } } else { ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogWarning((object)("Enemy names file not found: " + enemyPath)); } CreateDefaultNameFile(enemyPath, isAlly: false); } } catch (Exception ex) { ManualLogSource obj5 = logger; if (obj5 != null) { obj5.LogError((object)("Failed to load name lists: " + ex.Message)); } } } private void CreateDefaultNameFile(string path, bool isAlly) { try { string directoryName = Path.GetDirectoryName(path); if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } string[] array = ((!isAlly) ? new string[6] { "# Enemy Sosig Names", "Hostile Bot", "Attacker", "Enemy", "Threat", "Opponent" } : new string[6] { "# Ally Sosig Names", "Friendly Bot", "Guardian", "Protector", "Ally", "Helper" }); File.WriteAllLines(path, array); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Created default name file: " + path)); } if (isAlly) { for (int i = 1; i < array.Length; i++) { allyNames.Add(array[i]); } } else { for (int j = 1; j < array.Length; j++) { enemyNames.Add(array[j]); } } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to create default name file: " + ex.Message)); } } } public string GetRandomName(bool isAlly, SteamFriendsIntegration steamFriends = null, bool useSteamFriends = false) { if ((Object)(object)steamFriends != (Object)null && steamFriends.IsAvailable() && useSteamFriends) { try { string randomFriendName = steamFriends.GetRandomFriendName(); if (!string.IsNullOrEmpty(randomFriendName) && randomFriendName != "Steam Friend") { return randomFriendName; } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Failed to get Steam friend name: " + ex.Message)); } } } List list = (isAlly ? allyNames : enemyNames); if (list.Count == 0) { return isAlly ? "Ally" : "Enemy"; } return list[Random.Range(0, list.Count)]; } } public class SosigNameplateManager { public void AttachNameplate(Sosig sosig, string name, GameObject nameplatePrefab, bool isEnemy) { //IL_004d: 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) try { if (sosig.Links.Count != 0 && !((Object)(object)nameplatePrefab == (Object)null)) { GameObject val = Object.Instantiate(nameplatePrefab, ((Component)sosig.Links[0]).transform, false); val.transform.localPosition = new Vector3(0f, 0.3f, 0f); val.transform.localRotation = Quaternion.identity; Text[] componentsInChildren = val.GetComponentsInChildren(); Text[] array = componentsInChildren; foreach (Text val2 in array) { val2.text = name; } } } catch (Exception) { } } } public class SosigSpawnConfig { public ConfigEntry maxAllySosigs; public ConfigEntry maxEnemySosigs; public ConfigEntry spawnCooldown; public ConfigEntry enableNameplates; public ConfigEntry sosigLifetime; public ConfigEntry enableAutoCleanup; public ConfigEntry enemyIFF; public ConfigEntry followDistance; public ConfigEntry enemyAggressionDistance; public ConfigEntry useModernSpawnSystem; public ConfigEntry allySosigPool; public ConfigEntry enemySosigPool; public ConfigEntry enableArmorCustomization; public ConfigEntry maxSosigsPerUser; public ConfigEntry enableCoverAI; public ConfigEntry sosigUpdateInterval; public ConfigEntry enableChatWatcherIntegration; public List allyPoolIDs = new List(); public List enemyPoolIDs = new List(); public SosigEnemyID defaultAllyID = (SosigEnemyID)100; public SosigEnemyID defaultEnemyID = (SosigEnemyID)108; private ManualLogSource logger; public void Initialize(ConfigFile config, ManualLogSource logSource) { logger = logSource; maxAllySosigs = config.Bind("Chat Spawner", "MaxAllySosigs", 8, "Maximum ally sosigs"); maxEnemySosigs = config.Bind("Chat Spawner", "MaxEnemySosigs", 8, "Maximum enemy sosigs"); spawnCooldown = config.Bind("Chat Spawner", "SpawnCooldown", 2f, "Cooldown between spawns"); enableNameplates = config.Bind("Chat Spawner", "EnableNameplates", true, "Show nameplates above sosigs"); sosigLifetime = config.Bind("Chat Spawner", "SosigLifetime", 300f, "Sosig lifetime in seconds (0 = infinite)"); enableAutoCleanup = config.Bind("Chat Spawner", "EnableAutoCleanup", true, "Auto cleanup dead sosigs"); enemyIFF = config.Bind("Chat Spawner", "EnemyIFF", 1f, "Enemy IFF code"); followDistance = config.Bind("Chat Spawner", "FollowDistance", 6f, "Distance for allies to follow player"); enemyAggressionDistance = config.Bind("Chat Spawner", "EnemyAggressionDistance", 20f, "Distance at which enemies become aggressive"); useModernSpawnSystem = config.Bind("Chat Spawner", "UseModernSpawnSystem", true, "Use Update 120's modern TNH sosig spawn system (recommended)"); allySosigPool = config.Bind("Chat Spawner", "AllySosigPool", "M_Swat_Scout,M_Swat_Sniper,M_Swat_Breacher", "Comma-separated list of SosigEnemyID names for allies"); enemySosigPool = config.Bind("Chat Spawner", "EnemySosigPool", "M_Swat_Heavy,M_Swat_Breacher,M_Swat_Sniper", "Comma-separated list of SosigEnemyID names for enemies"); enableArmorCustomization = config.Bind("Chat Spawner Advanced", "EnableArmorCustomization", true, "Enable armor customization system"); maxSosigsPerUser = config.Bind("Chat Spawner Advanced", "MaxSosigsPerUser", 2, "Maximum sosigs per Twitch user"); enableCoverAI = config.Bind("Chat Spawner Advanced", "EnableCoverAI", true, "Enable advanced cover-taking AI behavior"); sosigUpdateInterval = config.Bind("Chat Spawner Advanced", "UpdateInterval", 1f, "Interval between sosig AI updates (seconds)"); enableChatWatcherIntegration = config.Bind("Chat Spawner Integration", "EnableChatWatcher", true, "Enable ChatWatcher integration for file-based Twitch chat spawning"); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Sosig spawn configuration initialized"); } } public void InitializeSosigPools() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) try { string[] array = allySosigPool.Value.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text in array2) { try { SosigEnemyID item = (SosigEnemyID)Enum.Parse(typeof(SosigEnemyID), text.Trim()); allyPoolIDs.Add(item); } catch { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Invalid ally sosig ID: " + text)); } } } string[] array3 = enemySosigPool.Value.Split(new char[1] { ',' }); string[] array4 = array3; foreach (string text2 in array4) { try { SosigEnemyID item2 = (SosigEnemyID)Enum.Parse(typeof(SosigEnemyID), text2.Trim()); enemyPoolIDs.Add(item2); } catch { ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogWarning((object)("Invalid enemy sosig ID: " + text2)); } } } if (allyPoolIDs.Count == 0) { allyPoolIDs.Add((SosigEnemyID)100); allyPoolIDs.Add((SosigEnemyID)102); } if (enemyPoolIDs.Count == 0) { enemyPoolIDs.Add((SosigEnemyID)108); enemyPoolIDs.Add((SosigEnemyID)109); } ManualLogSource obj5 = logger; if (obj5 != null) { obj5.LogInfo((object)$"Loaded {allyPoolIDs.Count} ally sosig types, {enemyPoolIDs.Count} enemy sosig types"); } } catch (Exception ex) { ManualLogSource obj6 = logger; if (obj6 != null) { obj6.LogError((object)("Failed to initialize sosig pools: " + ex.Message)); } allyPoolIDs.Add((SosigEnemyID)100); enemyPoolIDs.Add((SosigEnemyID)108); } } public SosigEnemyID GetRandomAllyID() { //IL_0033: 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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (allyPoolIDs.Count == 0) { return defaultAllyID; } return allyPoolIDs[Random.Range(0, allyPoolIDs.Count)]; } public SosigEnemyID GetRandomEnemyID() { //IL_0033: 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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (enemyPoolIDs.Count == 0) { return defaultEnemyID; } return enemyPoolIDs[Random.Range(0, enemyPoolIDs.Count)]; } } public class SosigSpawner { private ManualLogSource logger; private SosigTemplateCache templateCache; public void Initialize(ManualLogSource logSource, SosigTemplateCache cache) { logger = logSource; templateCache = cache; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"[SosigSpawner] Initialized"); } } public Sosig SpawnModern(SosigEnemyID enemyID, Vector3 pos, Quaternion rot, int IFF) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_00db: Unknown result type (might be due to invalid IL or missing references) try { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"[SosigSpawner] SpawnModern called - ID: {enemyID}, Pos: {pos}, IFF: {IFF}"); } if (templateCache == null) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)"[SosigSpawner] templateCache is null!"); } return null; } SosigEnemyTemplate template = templateCache.GetTemplate(enemyID); if ((Object)(object)template == (Object)null) { ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogError((object)$"[SosigSpawner] Could not find template for SosigEnemyID: {enemyID}"); } return null; } ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogInfo((object)("[SosigSpawner] Got template: " + (template.DisplayName ?? ((object)(SosigEnemyID)(ref template.SosigEnemyID)).ToString()))); } Sosig val = SpawnLegacy(template, pos, rot, IFF); if ((Object)(object)val == (Object)null) { ManualLogSource obj5 = logger; if (obj5 != null) { obj5.LogError((object)"[SosigSpawner] SpawnLegacy returned null"); } return null; } ManualLogSource obj6 = logger; if (obj6 != null) { obj6.LogInfo((object)"[SosigSpawner] SpawnModern completed successfully"); } return val; } catch (Exception ex) { ManualLogSource obj7 = logger; if (obj7 != null) { obj7.LogError((object)("[SosigSpawner] SpawnModern failed: " + ex.Message + "\n" + ex.StackTrace)); } return null; } } public Sosig SpawnLegacy(SosigEnemyTemplate template, Vector3 pos, Quaternion rot, int IFF) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_012d: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) try { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"[SosigSpawner] SpawnLegacy called - Template: {template?.SosigEnemyID}, Pos: {pos}"); } if ((Object)(object)template == (Object)null || template.SosigPrefabs == null || template.SosigPrefabs.Count == 0) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)"[SosigSpawner] Invalid template or no prefabs available"); } return null; } FVRObject val = template.SosigPrefabs[Random.Range(0, template.SosigPrefabs.Count)]; if ((Object)(object)val == (Object)null) { ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogError((object)"[SosigSpawner] Prefab is null"); } return null; } GameObject gameObject = ((AnvilAsset)val).GetGameObject(); if ((Object)(object)gameObject == (Object)null) { ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogError((object)"[SosigSpawner] prefab.GetGameObject() returned null"); } return null; } ManualLogSource obj5 = logger; if (obj5 != null) { obj5.LogInfo((object)$"[SosigSpawner] Instantiating prefab at {pos}"); } GameObject val2 = Object.Instantiate(gameObject, pos, rot); Sosig componentInChildren = val2.GetComponentInChildren(); if ((Object)(object)componentInChildren == (Object)null) { ManualLogSource obj6 = logger; if (obj6 != null) { obj6.LogError((object)"[SosigSpawner] No Sosig component found on instantiated object"); } Object.Destroy((Object)(object)val2); return null; } ManualLogSource obj7 = logger; if (obj7 != null) { obj7.LogInfo((object)"[SosigSpawner] Sosig component found, configuring..."); } if (template.ConfigTemplates != null && template.ConfigTemplates.Count > 0) { SosigConfigTemplate val3 = template.ConfigTemplates[Random.Range(0, template.ConfigTemplates.Count)]; if ((Object)(object)val3 != (Object)null) { componentInChildren.Configure(val3); } } componentInChildren.E.IFFCode = IFF; componentInChildren.SetIFF(IFF); if (componentInChildren.Priority.IFFChart != null) { for (int i = 0; i < componentInChildren.Priority.IFFChart.Length; i++) { componentInChildren.Priority.IFFChart[i] = i != IFF; } } int armorLevel = ((IFF == 0) ? SosigCustomizationUI.AllyArmor.Value : SosigCustomizationUI.EnemyArmor.Value); SosigArmorManager.ApplyArmorToSosig(componentInChildren, armorLevel); EquipWeapons(componentInChildren, template, pos, rot); try { componentInChildren.Inventory.FillAllAmmo(); } catch (Exception ex) { ManualLogSource obj8 = logger; if (obj8 != null) { obj8.LogWarning((object)("[SosigSpawner] Failed to fill ammo: " + ex.Message)); } } if (template.OutfitConfig != null && template.OutfitConfig.Count > 0) { ApplyOutfit(componentInChildren, template.OutfitConfig[Random.Range(0, template.OutfitConfig.Count)]); } ManualLogSource obj9 = logger; if (obj9 != null) { obj9.LogInfo((object)"[SosigSpawner] SpawnLegacy completed successfully"); } return componentInChildren; } catch (Exception ex2) { ManualLogSource obj10 = logger; if (obj10 != null) { obj10.LogError((object)("Legacy sosig spawn failed: " + ex2.Message)); } return null; } } private void EquipWeapons(Sosig sosig, SosigEnemyTemplate template, Vector3 pos, Quaternion rot) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (!SosigCustomizationUI.EnableGuns.Value) { return; } try { if (template.WeaponOptions != null && template.WeaponOptions.Count > 0) { EquipWeapon(sosig, template.WeaponOptions[Random.Range(0, template.WeaponOptions.Count)], pos, rot); } if (template.WeaponOptions_Secondary != null && template.WeaponOptions_Secondary.Count > 0) { EquipWeapon(sosig, template.WeaponOptions_Secondary[Random.Range(0, template.WeaponOptions_Secondary.Count)], pos, rot); } if (template.WeaponOptions_Tertiary != null && template.WeaponOptions_Tertiary.Count > 0) { EquipWeapon(sosig, template.WeaponOptions_Tertiary[Random.Range(0, template.WeaponOptions_Tertiary.Count)], pos, rot); } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Weapon equip failed: " + ex.Message)); } } } private void EquipWeapon(Sosig sosig, FVRObject weaponObj, Vector3 pos, Quaternion rot) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0033: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 //IL_008d: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)((weaponObj != null) ? ((AnvilAsset)weaponObj).GetGameObject() : null) == (Object)null) { return; } GameObject val = Object.Instantiate(((AnvilAsset)weaponObj).GetGameObject(), pos + Vector3.up * 0.1f, rot); SosigWeapon component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.SetAutoDestroy(true); component.O.SpawnLockable = false; component.SetAmmoClamping(true); component.IsShakeReloadable = false; if ((int)component.Type == 0) { sosig.Inventory.FillAmmoWithType(component.AmmoType); } sosig.Inventory.Init(); sosig.Inventory.FillAllAmmo(); sosig.InitHands(); sosig.ForceEquip(component); } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Weapon equip error: " + ex.Message)); } } } private void ApplyOutfit(Sosig sosig, SosigOutfitConfig outfit) { try { if (!((Object)(object)outfit == (Object)null) && sosig.Links.Count >= 4) { if (Random.value < outfit.Chance_Headwear) { SpawnAccessory(outfit.Headwear, sosig.Links[0]); } if (Random.value < outfit.Chance_Facewear) { SpawnAccessory(outfit.Facewear, sosig.Links[0]); } if (Random.value < outfit.Chance_Eyewear) { SpawnAccessory(outfit.Eyewear, sosig.Links[0]); } if (Random.value < outfit.Chance_Torsowear) { SpawnAccessory(outfit.Torsowear, sosig.Links[1]); } if (Random.value < outfit.Chance_Pantswear) { SpawnAccessory(outfit.Pantswear, sosig.Links[2]); } if (sosig.Links.Count > 3 && Random.value < outfit.Chance_Pantswear_Lower) { SpawnAccessory(outfit.Pantswear_Lower, sosig.Links[3]); } if (Random.value < outfit.Chance_Backpacks) { SpawnAccessory(outfit.Backpacks, sosig.Links[1]); } if (Random.value < outfit.Chance_TorosDecoration) { SpawnAccessory(outfit.TorosDecoration, sosig.Links[1]); } } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Outfit apply failed: " + ex.Message)); } } } private void SpawnAccessory(List accessories, SosigLink link) { //IL_005a: 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) if (accessories == null || accessories.Count == 0 || (Object)(object)link == (Object)null) { return; } try { FVRObject val = accessories[Random.Range(0, accessories.Count)]; if (!((Object)(object)((val != null) ? ((AnvilAsset)val).GetGameObject() : null) == (Object)null)) { GameObject val2 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), ((Component)link).transform.position, ((Component)link).transform.rotation); val2.transform.SetParent(((Component)link).transform); SosigWearable component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { component.RegisterWearable(link); } } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Accessory spawn failed: " + ex.Message)); } } } } public class SosigSpawnPositionCalculator { public Vector3 CalculateAllySpawnPoint() { //IL_0065: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00d3: 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_004f: 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) if ((Object)(object)GM.CurrentPlayerBody == (Object)null || (Object)(object)GM.CurrentPlayerBody.Head == (Object)null || (Object)(object)((Component)GM.CurrentPlayerBody.Head).transform == (Object)null) { Debug.LogWarning((object)"[H3TVR] CalculateAllySpawnPoint: Player not ready"); return Vector3.zero; } Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position; float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f); float num2 = Random.Range(2f, 4f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x + Mathf.Cos(num) * num2, position.y, position.z + Mathf.Sin(num) * num2); Debug.Log((object)$"[H3TVR] Ally spawn position calculated: {val}"); return val; } public Vector3 CalculateEnemySpawnPoint() { //IL_0065: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00d3: 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_004f: 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) if ((Object)(object)GM.CurrentPlayerBody == (Object)null || (Object)(object)GM.CurrentPlayerBody.Head == (Object)null || (Object)(object)((Component)GM.CurrentPlayerBody.Head).transform == (Object)null) { Debug.LogWarning((object)"[H3TVR] CalculateEnemySpawnPoint: Player not ready"); return Vector3.zero; } Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position; float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f); float num2 = Random.Range(8f, 15f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x + Mathf.Cos(num) * num2, position.y, position.z + Mathf.Sin(num) * num2); Debug.Log((object)$"[H3TVR] Enemy spawn position calculated: {val}"); return val; } public Vector3 CalculateBossSpawnPoint() { //IL_0065: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00d3: 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_004f: 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) if ((Object)(object)GM.CurrentPlayerBody == (Object)null || (Object)(object)GM.CurrentPlayerBody.Head == (Object)null || (Object)(object)((Component)GM.CurrentPlayerBody.Head).transform == (Object)null) { Debug.LogWarning((object)"[H3TVR] CalculateBossSpawnPoint: Player not ready"); return Vector3.zero; } Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position; float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f); float num2 = Random.Range(20f, 30f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x + Mathf.Cos(num) * num2, position.y, position.z + Mathf.Sin(num) * num2); Debug.Log((object)$"[H3TVR] Boss spawn position calculated: {val}"); return val; } public bool IsPlayerReady() { return (Object)(object)GM.CurrentPlayerBody != (Object)null && (Object)(object)GM.CurrentPlayerBody.Head != (Object)null && (Object)(object)((Component)GM.CurrentPlayerBody.Head).transform != (Object)null; } } public class SosigTemplateCache { private Dictionary templateCache = new Dictionary(); private ManualLogSource logger; public void Initialize(ManualLogSource logSource) { logger = logSource; } public void BuildCache(List allyPoolIDs, List enemyPoolIDs) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0147: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)ManagerSingleton.Instance == (Object)null) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)"Cannot build template cache - IM.Instance is null"); } return; } if (ManagerSingleton.Instance.odicSosigObjsByID == null) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogWarning((object)"Cannot build template cache - odicSosigObjsByID is null"); } return; } int num = 0; ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogInfo((object)"Building template cache from IM.Instance..."); } foreach (SosigEnemyID item in allyPoolIDs.Concat(enemyPoolIDs).Distinct()) { if (ManagerSingleton.Instance.odicSosigObjsByID.ContainsKey(item)) { SosigEnemyTemplate val = ManagerSingleton.Instance.odicSosigObjsByID[item]; if ((Object)(object)val != (Object)null) { templateCache[item] = val; num++; ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogDebug((object)$" Cached: {item}"); } } else { ManualLogSource obj5 = logger; if (obj5 != null) { obj5.LogWarning((object)$" Template null for {item}"); } } } else { ManualLogSource obj6 = logger; if (obj6 != null) { obj6.LogWarning((object)$" ID not found in IM: {item}"); } } } ManualLogSource obj7 = logger; if (obj7 != null) { obj7.LogInfo((object)$"Template cache built: {num}/{allyPoolIDs.Count + enemyPoolIDs.Count} templates loaded"); } ManualLogSource obj8 = logger; if (obj8 != null) { obj8.LogInfo((object)$"Template cache status: {templateCache.Count} total templates"); } } catch (Exception ex) { ManualLogSource obj9 = logger; if (obj9 != null) { obj9.LogWarning((object)("Failed to build template cache: " + ex.Message)); } } } public SosigEnemyTemplate GetTemplate(SosigEnemyID enemyID) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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_0120: Unknown result type (might be due to invalid IL or missing references) if (templateCache.ContainsKey(enemyID)) { return templateCache[enemyID]; } if ((Object)(object)ManagerSingleton.Instance != (Object)null && ManagerSingleton.Instance.odicSosigObjsByID != null && ManagerSingleton.Instance.odicSosigObjsByID.ContainsKey(enemyID)) { SosigEnemyTemplate val = ManagerSingleton.Instance.odicSosigObjsByID[enemyID]; templateCache[enemyID] = val; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"Cached template for {enemyID} from IM.Instance"); } return val; } ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogWarning((object)$"Template not in cache for {enemyID}, searching Resources..."); } SosigEnemyTemplate[] array = Resources.FindObjectsOfTypeAll(); SosigEnemyTemplate[] array2 = array; foreach (SosigEnemyTemplate val2 in array2) { if ((Object)(object)val2 != (Object)null && val2.SosigEnemyID == enemyID) { templateCache[enemyID] = val2; ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogInfo((object)$"Found and cached template for {enemyID}"); } return val2; } } ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogError((object)$"Could not find template for SosigEnemyID: {enemyID}"); } return null; } public bool HasTemplate(SosigEnemyID enemyID) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return templateCache.ContainsKey(enemyID); } public int GetCacheSize() { return templateCache.Count; } } public enum SpawnPriority { Low, Normal, High, Immediate } public class ChatWatcher : MonoBehaviour { private struct ParsedContentResult { public List Usernames; public List> ArmorCommands; public List UserArmorCommands; } private struct UserArmorCommand { public string Username; public int ArmorLevel; public string ArmorName; } public struct ChatWatcherStats { public bool FileWatchingActive; public int ProcessedUsernames; public int ActiveAllies; public int ActiveEnemies; public int TotalActiveSosigs; } private H3TVRImproved plugin; private ManualLogSource logger; private AdvancedChatSosigSpawner sosigSpawner; private ConfigEntry enableFileWatching; private ConfigEntry allyChatFilePath; private ConfigEntry enemyChatFilePath; private ConfigEntry fileCheckInterval; private ConfigEntry clearFileAfterRead; private float lastFileCheckTime; private string lastAllyFileContent = ""; private string lastEnemyFileContent = ""; private HashSet processedUsernames = new HashSet(); public static ChatWatcher Instance { get; private set; } public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource, AdvancedChatSosigSpawner spawner) { if ((Object)(object)Instance != (Object)null) { Object.Destroy((Object)(object)this); return; } Instance = this; plugin = pluginInstance; logger = logSource; sosigSpawner = spawner; InitializeConfiguration(); if (enableFileWatching.Value) { InitializeFileWatching(); } ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Chat Watcher initialized (H3TwitchTools compatible file mode - Channel Points ready)"); } } private void InitializeConfiguration() { H3TVRImproved h3TVRImproved = plugin; if (((h3TVRImproved != null) ? ((BaseUnityPlugin)h3TVRImproved).Config : null) == null) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)"Plugin config is null"); } return; } try { enableFileWatching = ((BaseUnityPlugin)plugin).Config.Bind("Chat Watcher - File Mode", "EnableFileWatching", true, "Enable file watching mode for chat integration (H3TwitchTools style)"); allyChatFilePath = ((BaseUnityPlugin)plugin).Config.Bind("Chat Watcher - File Mode", "AllyChatFilePath", "BepInEx/config/H3TVR_AllyChat.txt", "Path to ally chat file\nSUPPORTED FORMATS:\n - Plain username: ViewerName\n - Key=Value: username=ViewerName\n - Key=Value: user=ViewerName\n - Key=Value: redeemer=ViewerName\nSUPPORTS ABSOLUTE PATHS: C:\\StreamFiles\\ally_chat.txt\nOr relative: BepInEx/config/H3TVR_AllyChat.txt"); enemyChatFilePath = ((BaseUnityPlugin)plugin).Config.Bind("Chat Watcher - File Mode", "EnemyChatFilePath", "BepInEx/config/H3TVR_EnemyChat.txt", "Path to enemy chat file\nSUPPORTED FORMATS:\n - Plain username: ViewerName\n - Key=Value: username=ViewerName\n - Key=Value: user=ViewerName\n - Key=Value: redeemer=ViewerName\nSUPPORTS ABSOLUTE PATHS: C:\\StreamFiles\\enemy_chat.txt\nOr relative: BepInEx/config/H3TVR_EnemyChat.txt"); fileCheckInterval = ((BaseUnityPlugin)plugin).Config.Bind("Chat Watcher - File Mode", "FileCheckInterval", 0.5f, "How often to check files for changes (seconds)"); clearFileAfterRead = ((BaseUnityPlugin)plugin).Config.Bind("Chat Watcher - File Mode", "ClearFileAfterRead", true, "Clear chat file after reading usernames (recommended for channel points)"); ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)"Chat Watcher configuration initialized (Channel Points format supported)"); } } catch (Exception ex) { ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogError((object)("Chat Watcher config init failed: " + ex.Message)); } } } private void InitializeFileWatching() { try { string text = ResolveFilePath(allyChatFilePath.Value); CreateFileIfNotExists(text, isAlly: true); string text2 = ResolveFilePath(enemyChatFilePath.Value); CreateFileIfNotExists(text2, isAlly: false); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"File watching initialized (Channel Points ready)"); } ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)(" Ally file: " + text)); } ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogInfo((object)(" Enemy file: " + text2)); } } catch (Exception ex) { ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogError((object)("File watching init failed: " + ex.Message)); } } } private void CreateFileIfNotExists(string filePath, bool isAlly) { try { if (!File.Exists(filePath)) { string directoryName = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } string contents = "# H3TVR " + (isAlly ? "Ally" : "Enemy") + " Chat File (Channel Points Compatible)\n# SUPPORTED FORMATS:\n# Plain username: ViewerName\n# Key=Value: username=ViewerName\n# Key=Value: user=ViewerName\n# Key=Value: redeemer=ViewerName\n# File will be cleared after reading if ClearFileAfterRead is enabled\n# Perfect for Twitch Channel Points redemptions!\n"; File.WriteAllText(filePath, contents); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Created chat file: " + filePath)); } } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to create file " + filePath + ": " + ex.Message)); } } } private void Update() { try { if (enableFileWatching.Value && Time.time - lastFileCheckTime >= fileCheckInterval.Value) { CheckChatFiles(); lastFileCheckTime = Time.time; } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Update loop error: " + ex.Message)); } } } public void SpawnManualAlly() { try { string text = "Player_" + Random.Range(1000, 9999); sosigSpawner?.SpawningSequence(text); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Manually spawned ally: " + text)); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Manual ally spawn failed: " + ex.Message)); } } } public void SpawnManualEnemy() { try { string text = "Enemy_" + Random.Range(1000, 9999); sosigSpawner?.SpawningSequenceEnemy(1, text); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Manually spawned enemy: " + text)); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Manual enemy spawn failed: " + ex.Message)); } } } public void ClearAllSosigs() { try { sosigSpawner?.ClearSosigs(); processedUsernames.Clear(); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Cleared all chat sosigs"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Clear sosigs failed: " + ex.Message)); } } } private void CheckChatFiles() { string text = ResolveFilePath(allyChatFilePath.Value); if (File.Exists(text)) { ProcessChatFile(text, isAlly: true); } string text2 = ResolveFilePath(enemyChatFilePath.Value); if (File.Exists(text2)) { ProcessChatFile(text2, isAlly: false); } } private void ProcessChatFile(string filePath, bool isAlly) { try { string text = File.ReadAllText(filePath); string text2 = (isAlly ? lastAllyFileContent : lastEnemyFileContent); if (text == text2) { return; } if (isAlly) { lastAllyFileContent = text; } else { lastEnemyFileContent = text; } if (string.IsNullOrEmpty(text) || text.Trim().Length == 0) { return; } ParsedContentResult parsedContentResult = ParseContent(text); if (parsedContentResult.ArmorCommands.Count > 0) { foreach (KeyValuePair armorCommand in parsedContentResult.ArmorCommands) { if (armorCommand.Key == "ally_armor") { SosigCustomizationUI.AllyArmor.Value = armorCommand.Value; SosigArmorManager.SetGlobalDefaults(armorCommand.Value, SosigCustomizationUI.EnemyArmor.Value); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Set ally armor to " + SosigArmorManager.GetArmorName(armorCommand.Value))); } } else if (armorCommand.Key == "enemy_armor") { SosigCustomizationUI.EnemyArmor.Value = armorCommand.Value; SosigArmorManager.SetGlobalDefaults(SosigCustomizationUI.AllyArmor.Value, armorCommand.Value); ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)("Set enemy armor to " + SosigArmorManager.GetArmorName(armorCommand.Value))); } } } } foreach (UserArmorCommand userArmorCommand in parsedContentResult.UserArmorCommands) { if (!string.IsNullOrEmpty(userArmorCommand.Username)) { SosigArmorManager.SetUserArmorPreference(userArmorCommand.Username, userArmorCommand.ArmorLevel); ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogInfo((object)("[ARMOR] " + userArmorCommand.Username + " set armor to " + userArmorCommand.ArmorName)); } continue; } SosigCustomizationUI.SetAllyArmor(userArmorCommand.ArmorLevel); SosigCustomizationUI.SetEnemyArmor(userArmorCommand.ArmorLevel); SosigArmorManager.SetGlobalDefaults(userArmorCommand.ArmorLevel, userArmorCommand.ArmorLevel); ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogInfo((object)("[ARMOR] Global armor set to " + userArmorCommand.ArmorName)); } } foreach (string username in parsedContentResult.Usernames) { if (processedUsernames.Contains(username)) { continue; } if (isAlly) { sosigSpawner?.SpawningSequence(username); ManualLogSource obj5 = logger; if (obj5 != null) { obj5.LogInfo((object)("Channel Point: Spawned ally for " + username + " (Armor: " + SosigArmorManager.GetArmorName(SosigArmorManager.GetUserArmorPreference(username, isAlly: true)) + ")")); } } else { sosigSpawner?.SpawningSequenceEnemy(1, username); ManualLogSource obj6 = logger; if (obj6 != null) { obj6.LogInfo((object)("Channel Point: Spawned enemy for " + username + " (Armor: " + SosigArmorManager.GetArmorName(SosigArmorManager.GetUserArmorPreference(username, isAlly: false)) + ")")); } } processedUsernames.Add(username); } if (clearFileAfterRead.Value && (parsedContentResult.Usernames.Count > 0 || parsedContentResult.ArmorCommands.Count > 0)) { ClearChatFile(filePath, isAlly); } if (processedUsernames.Count > 1000) { processedUsernames.Clear(); } } catch (Exception ex) { ManualLogSource obj7 = logger; if (obj7 != null) { obj7.LogError((object)("Failed to process chat file " + filePath + ": " + ex.Message)); } } } private ParsedContentResult ParseContent(string content) { ParsedContentResult parsedContentResult = default(ParsedContentResult); parsedContentResult.Usernames = new List(); parsedContentResult.ArmorCommands = new List>(); parsedContentResult.UserArmorCommands = new List(); ParsedContentResult result = parsedContentResult; try { string[] array = content.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (string.IsNullOrEmpty(text2) || text2.StartsWith("#") || text2.StartsWith(";")) { continue; } if (TryParseUserArmorCommand(text2, out var cmd)) { result.UserArmorCommands.Add(cmd); ManualLogSource obj = logger; if (obj != null) { obj.LogDebug((object)("User armor command: " + cmd.Username + " -> " + cmd.ArmorName)); } continue; } if (TryParseArmorCommand(text2, out KeyValuePair command)) { result.ArmorCommands.Add(command); ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogDebug((object)$"Parsed armor command: '{command.Key}={command.Value}'"); } continue; } if (TryParseAirdropCommand(text2, out string username)) { plugin.GetAirdropManager()?.CallAirdrop(username); continue; } if (TryParseNukeCommand(text2)) { plugin.GetSpawnManager()?.SpawnNuke(); ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogInfo((object)"[NUKE] Nuclear strike triggered!"); } continue; } if (TryParseWarlordCommand(text2, out string bossName)) { plugin.GetSpawnManager()?.SpawnWarlordBoss(bossName); ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogInfo((object)("[WARLORD] Spawning Warlord boss named '" + bossName + "'!")); } continue; } string text3 = ExtractUsername(text2); if (!string.IsNullOrEmpty(text3)) { result.Usernames.Add(text3); ManualLogSource obj5 = logger; if (obj5 != null) { obj5.LogDebug((object)("Extracted username: '" + text3 + "' from line: '" + text2 + "'")); } } } } catch (Exception ex) { ManualLogSource obj6 = logger; if (obj6 != null) { obj6.LogError((object)("Failed to parse content: " + ex.Message)); } } return result; } private bool TryParseUserArmorCommand(string line, out UserArmorCommand cmd) { cmd = default(UserArmorCommand); string text = line.ToLower(); if (text.Contains(":!armor")) { int num = line.IndexOf(':'); if (num > 0) { string username = line.Substring(0, num).Trim(); string message = line.Substring(num + 1).Trim(); if (SosigArmorManager.TryParseArmorCommand(message, username, out int armorLevel, out string armorName)) { cmd = new UserArmorCommand { Username = username, ArmorLevel = armorLevel, ArmorName = armorName }; return true; } } } if (text.StartsWith("!armor") && SosigArmorManager.TryParseArmorCommand(line, null, out int armorLevel2, out string armorName2)) { cmd = new UserArmorCommand { Username = null, ArmorLevel = armorLevel2, ArmorName = armorName2 }; return true; } if (text.Contains("armor=") && (text.Contains("user=") || text.Contains("username="))) { string text2 = null; int level = 0; string[] array = line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text3 in array2) { if (text3.ToLower().StartsWith("user=") || text3.ToLower().StartsWith("username=")) { text2 = text3.Substring(text3.IndexOf('=') + 1).Trim(); } else if (text3.ToLower().StartsWith("armor=")) { string value = text3.Substring(6).Trim(); ParseArmorValue(value, out level); } } if (!string.IsNullOrEmpty(text2)) { SosigArmorManager.SetUserArmorPreference(text2, level); cmd = new UserArmorCommand { Username = text2, ArmorLevel = level, ArmorName = SosigArmorManager.GetArmorName(level) }; return true; } } return false; } private bool ParseArmorValue(string value, out int level) { level = 0; if (string.IsNullOrEmpty(value)) { return false; } if (int.TryParse(value, out level)) { level = Mathf.Clamp(level, 0, 5); return true; } switch (value.ToLower()) { case "none": case "off": level = 0; return true; case "light": case "l": level = 1; return true; case "medium": case "med": case "m": level = 2; return true; case "heavy": case "h": level = 3; return true; case "tank": case "juggernaut": case "jug": case "t": level = 4; return true; case "god": case "godmode": case "g": level = 5; return true; default: return false; } } private bool TryParseArmorCommand(string line, out KeyValuePair command) { command = default(KeyValuePair); if (!line.Contains("=")) { return false; } string[] array = line.Split(new char[1] { '=' }); if (array.Length < 2) { return false; } string text = array[0].Trim().ToLower(); if ((text == "ally_armor" || text == "enemy_armor") && int.TryParse(array[1].Trim(), out var result)) { command = new KeyValuePair(text, Mathf.Clamp(result, 0, 5)); return true; } return false; } private bool TryParseAirdropCommand(string line, out string username) { username = null; if (!line.Contains("=")) { return false; } string[] array = line.Split(new char[1] { '=' }); if (array.Length < 2) { return false; } string text = array[0].Trim().ToLower(); if (text == "airdrop") { username = array[1].Trim(); return true; } return false; } private bool TryParseNukeCommand(string line) { string text = line.ToLower().Trim(); if (text == "!nuke" || text == "nuke") { return true; } if (text.StartsWith("nuke=")) { string text2 = text.Substring(5).Trim(); return text2 == "1" || text2 == "true" || text2 == "yes"; } return false; } private bool TryParseWarlordCommand(string line, out string bossName) { bossName = null; string text = line.ToLower().Trim(); if (text.StartsWith("warlord=") || text.StartsWith("boss_warlord=")) { int num = line.IndexOf('='); if (num > 0 && num < line.Length - 1) { bossName = line.Substring(num + 1).Trim(); return !string.IsNullOrEmpty(bossName); } } if (text.StartsWith("!warlord ")) { bossName = line.Substring(9).Trim(); return !string.IsNullOrEmpty(bossName); } return false; } private List ParseUsernames(string content) { return ParseContent(content).Usernames; } private string ExtractUsername(string line) { if (string.IsNullOrEmpty(line)) { return null; } string text = line.Trim(); if (text.Contains("=")) { string[] array = text.Split(new char[1] { '=' }); if (array.Length >= 2) { string text2 = array[0].Trim().ToLower(); string text3 = array[1].Trim(); switch (text2) { default: if (!(text2 == "name")) { break; } goto case "username"; case "username": case "user": case "redeemer": { int num = text3.IndexOf('#'); if (num > 0) { text3 = text3.Substring(0, num).Trim(); } int num2 = text3.IndexOf(' '); if (num2 > 0) { text3 = text3.Substring(0, num2).Trim(); } if (!string.IsNullOrEmpty(text3)) { return text3; } break; } } } } if (text.Contains(" ")) { string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length != 0) { string text4 = array2[0].Trim(); if (!text4.StartsWith("[") && !text4.StartsWith("<") && !text4.EndsWith(":") && text4.Length > 0) { return text4; } } } if (text.Length > 0 && !text.StartsWith("[") && !text.StartsWith("<")) { return text; } return null; } private void ClearChatFile(string filePath, bool isAlly) { try { string contents = "# H3TVR " + (isAlly ? "Ally" : "Enemy") + " Chat File (Channel Points Compatible)\n# SUPPORTED FORMATS:\n# Plain username: ViewerName\n# Key=Value: username=ViewerName\n# Key=Value: user=ViewerName\n# Key=Value: redeemer=ViewerName\n"; File.WriteAllText(filePath, contents); if (isAlly) { lastAllyFileContent = ""; } else { lastEnemyFileContent = ""; } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Failed to clear file " + filePath + ": " + ex.Message)); } } } public void TriggerSpawn(string username, bool isAlly) { try { if (string.IsNullOrEmpty(username)) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)"Cannot spawn sosig - username is null or empty"); } return; } if (isAlly) { sosigSpawner?.SpawningSequence(username); ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)("API trigger: Spawned ally for " + username)); } } else { sosigSpawner?.SpawningSequenceEnemy(1, username); ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogInfo((object)("API trigger: Spawned enemy for " + username)); } } processedUsernames.Add(username); } catch (Exception ex) { ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogError((object)("API spawn trigger failed: " + ex.Message)); } } } public ChatWatcherStats GetStats() { AdvancedChatSosigSpawner.SosigStats sosigStats = sosigSpawner?.GetStats() ?? default(AdvancedChatSosigSpawner.SosigStats); ChatWatcherStats result = default(ChatWatcherStats); result.FileWatchingActive = enableFileWatching.Value; result.ProcessedUsernames = processedUsernames.Count; result.ActiveAllies = sosigStats.Allies; result.ActiveEnemies = sosigStats.Enemies; result.TotalActiveSosigs = sosigStats.TotalActive; return result; } public void ClearCache() { processedUsernames.Clear(); lastAllyFileContent = ""; lastEnemyFileContent = ""; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Cleared chat watcher cache"); } } private string ResolveFilePath(string configuredPath) { if (string.IsNullOrEmpty(configuredPath)) { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)plugin).Info.Location); string path = Path.Combine(directoryName, ".."); string path2 = Path.Combine(path, "config"); return Path.Combine(path2, "H3TVR_Chat.txt"); } if (Path.IsPathRooted(configuredPath)) { return configuredPath; } string directoryName2 = Path.GetDirectoryName(((BaseUnityPlugin)plugin).Info.Location); string text = Path.Combine(directoryName2, configuredPath); if (File.Exists(text)) { return text; } string directoryName3 = Path.GetDirectoryName(directoryName2); string text2 = Path.Combine(directoryName3, configuredPath); if (File.Exists(text2)) { return text2; } return text; } private void OnDestroy() { try { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Chat Watcher cleaned up"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Chat Watcher cleanup failed: " + ex.Message)); } } } } public class ConfigurationManager { private readonly ConfigFile config; private readonly ManualLogSource logger; private float cachedMaxSlomo; private float cachedSlomoWaitTime; private float cachedSlomoScaleSpeed; private float cachedSlomoReturnSpeed; private bool cachedSlomoUseRamp; private string cachedSlomoRampCurve; private float cachedSlomoRampDuration; private float cachedSlomoReturnRampDuration; private bool cachedSlomoAffectsAudio; private float cachedSlomoAudioPitchScale; private bool cachedSlomoAudioPreservePitch; private bool cachedSlomoAffectsAudioSpeed; private float cachedSlomoAudioSpeedScale; private string cachedSlomoAudioMode; private bool cachedEnableInfiniteTokens; private bool cachedDisableEncryptionNodes; private bool cachedDisableAllEncryptions; public ConfigEntry MaxSlomo { get; private set; } public ConfigEntry SlomoWaitTime { get; private set; } public ConfigEntry SlomoScaleSpeed { get; private set; } public ConfigEntry SlomoReturnSpeed { get; private set; } public ConfigEntry SlomoVRControllerEnabled { get; private set; } public ConfigEntry SlomoVRButton { get; private set; } public ConfigEntry SlomoAffectsMovement { get; private set; } public ConfigEntry SlomoMovementScale { get; private set; } public ConfigEntry SlomoUseRampSpeed { get; private set; } public ConfigEntry SlomoRampCurve { get; private set; } public ConfigEntry SlomoRampDuration { get; private set; } public ConfigEntry SlomoReturnRampDuration { get; private set; } public ConfigEntry EnableKillSlomo { get; private set; } public ConfigEntry SlomoAffectsAudio { get; private set; } public ConfigEntry SlomoAudioPitchScale { get; private set; } public ConfigEntry SlomoAudioPreservePitch { get; private set; } public ConfigEntry SlomoAffectsAudioSpeed { get; private set; } public ConfigEntry SlomoAudioSpeedScale { get; private set; } public ConfigEntry SlomoAudioMode { get; private set; } public ConfigEntry UseItemManagerForGunRandomization { get; private set; } public ConfigEntry GunList { get; private set; } public ConfigEntry MagazineList { get; private set; } public ConfigEntry ShurikenScale { get; private set; } public ConfigEntry ShurikenMinCount { get; private set; } public ConfigEntry ShurikenMaxCount { get; private set; } public ConfigEntry PillowMinCount { get; private set; } public ConfigEntry PillowMaxCount { get; private set; } public ConfigEntry PillowGrenadeEnabled { get; private set; } public ConfigEntry PillowGrenadeChance { get; private set; } public ConfigEntry PillowGrenadeArmedChance { get; private set; } public ConfigEntry PillowZeroGravityEnabled { get; private set; } public ConfigEntry PillowZeroGravityChance { get; private set; } public ConfigEntry PillowZeroGravityDuration { get; private set; } public ConfigEntry PillowSlomoEnabled { get; private set; } public ConfigEntry PillowSlomoChance { get; private set; } public ConfigEntry PillowSlomoDuration { get; private set; } public ConfigEntry DangerCloseMinCount { get; private set; } public ConfigEntry DangerCloseMaxCount { get; private set; } public Dictionary> KeyBindings { get; private set; } = new Dictionary>(); public ConfigEntry EnableTwitchChatSosigs { get; private set; } public ConfigEntry EnableSteamFriends { get; private set; } public ConfigEntry SteamFriendsRandomNames { get; private set; } public ConfigEntry SteamFriendsRefreshInterval { get; private set; } public ConfigEntry EnableInfiniteTokens { get; private set; } public ConfigEntry DisableEncryptionNodes { get; private set; } public ConfigEntry DisableAllEncryptions { get; private set; } public ConfigEntry DisableEncryptionType1 { get; private set; } public ConfigEntry DisableEncryptionType2 { get; private set; } public ConfigEntry DisableEncryptionType3 { get; private set; } public ConfigEntry AutoCompleteEncryption { get; private set; } public ConfigEntry EncryptionCompletionDelay { get; private set; } public float CachedMaxSlomo => cachedMaxSlomo; public float CachedSlomoWaitTime => cachedSlomoWaitTime; public float CachedSlomoScaleSpeed => cachedSlomoScaleSpeed; public float CachedSlomoReturnSpeed => cachedSlomoReturnSpeed; public bool CachedSlomoUseRamp => cachedSlomoUseRamp; public string CachedSlomoRampCurve => cachedSlomoRampCurve; public float CachedSlomoRampDuration => cachedSlomoRampDuration; public float CachedSlomoReturnRampDuration => cachedSlomoReturnRampDuration; public bool CachedSlomoAffectsAudio => cachedSlomoAffectsAudio; public float CachedSlomoAudioPitchScale => cachedSlomoAudioPitchScale; public bool CachedSlomoAudioPreservePitch => cachedSlomoAudioPreservePitch; public bool CachedSlomoAffectsAudioSpeed => cachedSlomoAffectsAudioSpeed; public float CachedSlomoAudioSpeedScale => cachedSlomoAudioSpeedScale; public string CachedSlomoAudioMode => cachedSlomoAudioMode; public bool CachedEnableInfiniteTokens => cachedEnableInfiniteTokens; public bool CachedDisableEncryptionNodes => cachedDisableEncryptionNodes; public bool CachedDisableAllEncryptions => cachedDisableAllEncryptions; public ConfigurationManager(ConfigFile configFile, ManualLogSource logSource) { config = configFile; logger = logSource; } public void InitializeAll() { InitializeSlomoConfig(); InitializeAudioConfig(); InitializeGunRandomizationConfig(); InitializeSpawnConfigurations(); InitializeKeyBindings(); logger.LogInfo((object)"ConfigurationManager: All configuration entries initialized"); } private void InitializeSlomoConfig() { MaxSlomo = config.Bind("Slomo", "MaxSlowmoScale", 0.1f, "Maximum slomo scale (0.01 = 1% speed, 0.1 = 10% speed)"); SlomoWaitTime = config.Bind("Slomo", "WaitTime", 2f, "Time to wait at max slomo before returning to normal speed"); SlomoScaleSpeed = config.Bind("Slomo", "ScaleDownSpeed", 1f, "Speed at which time slows down (higher = faster transition)"); SlomoReturnSpeed = config.Bind("Slomo", "ReturnSpeed", 0.33f, "Speed at which time returns to normal (higher = faster return)"); SlomoVRControllerEnabled = config.Bind("Slomo", "VRControllerEnabled", true, "Enable VR controller button to trigger slomo"); SlomoVRButton = config.Bind("Slomo", "VRButton", "LeftX", "VR button to trigger slomo"); SlomoAffectsMovement = config.Bind("Slomo", "AffectsMovement", true, "Whether slomo affects player movement speed"); SlomoMovementScale = config.Bind("Slomo", "MovementScale", 0.3f, "Movement speed multiplier during slomo"); SlomoUseRampSpeed = config.Bind("Slomo.Ramp", "UseRampSpeed", true, "Enable smooth ramp speed transitions for slomo (more cinematic)"); SlomoRampCurve = config.Bind("Slomo.Ramp", "RampCurve", "EaseInOut", "Curve type for slomo ramp: Linear, EaseIn, EaseOut, EaseInOut, Smooth, Cinematic"); SlomoRampDuration = config.Bind("Slomo.Ramp", "RampDuration", 0.5f, "Duration in seconds for slomo to ramp down to max slow speed"); SlomoReturnRampDuration = config.Bind("Slomo.Ramp", "ReturnRampDuration", 0.8f, "Duration in seconds for slomo to ramp back to normal speed"); EnableKillSlomo = config.Bind("Slomo", "EnableKillSlomo", true, "Enable slow motion effect on enemy kill."); } private void InitializeAudioConfig() { SlomoAffectsAudio = config.Bind("Audio", "SlomoAffectsAudio", true, "Whether slomo affects audio pitch"); SlomoAudioPitchScale = config.Bind("Audio", "SlomoAudioPitchScale", 1f, "Audio pitch multiplier during slomo (1.0 = normal pitch, 0.5 = half pitch)"); SlomoAudioPreservePitch = config.Bind("Audio", "SlomoPreservePitch", false, "If true, audio pitch is preserved (no pitch change). If false, uses pitch scaling."); SlomoAffectsAudioSpeed = config.Bind("Audio", "SlomoAffectsAudioSpeed", false, "Whether slomo affects audio speed (time stretching)"); SlomoAudioSpeedScale = config.Bind("Audio", "SlomoAudioSpeedScale", 1f, "Audio speed multiplier during slomo (1.0 = normal speed, 0.5 = half speed)"); SlomoAudioMode = config.Bind("Audio", "SlomoAudioMode", "Both", "Audio adjustment mode during slomo: 'PitchOnly', 'SpeedOnly', 'Both', 'Independent'"); } private void InitializeGunRandomizationConfig() { UseItemManagerForGunRandomization = config.Bind("GunRandomization", "UseItemManager", true, "Use ItemManager for gun randomization (includes all H3VR and modded guns). If false, uses GunList/MagazineList config files."); GunList = config.Bind("General", "GunList", "DefaultGunList", "List of guns"); MagazineList = config.Bind("General", "MagazineList", "DefaultMagazineList", "List of magazines"); } private void InitializeSpawnConfigurations() { ShurikenScale = config.Bind("Shuriken", "Scale", 1f, "Scale multiplier for spawned shuriken"); ShurikenMinCount = config.Bind("Shuriken", "MinCount", 1, "Minimum number of shuriken to spawn"); ShurikenMaxCount = config.Bind("Shuriken", "MaxCount", 3, "Maximum number of shuriken to spawn"); PillowMinCount = config.Bind("Pillow", "MinCount", 1, "Minimum number of pillows to spawn"); PillowMaxCount = config.Bind("Pillow", "MaxCount", 3, "Maximum number of pillows to spawn"); PillowGrenadeEnabled = config.Bind("Pillow", "GrenadeEnabled", true, "Enable pillow grenade effect"); PillowGrenadeChance = config.Bind("Pillow", "GrenadeChance", 0.1f, "Chance for pillow to spawn grenade"); PillowGrenadeArmedChance = config.Bind("Pillow", "GrenadeArmedChance", 0.3f, "Chance for pillow grenade to be armed"); PillowZeroGravityEnabled = config.Bind("Pillow", "ZeroGEnabled", true, "Enable pillow zero gravity effect"); PillowZeroGravityChance = config.Bind("Pillow", "ZeroGChance", 0.15f, "Chance for pillow to trigger zero gravity"); PillowZeroGravityDuration = config.Bind("Pillow", "ZeroGDuration", 10f, "Duration of pillow zero gravity effect"); PillowSlomoEnabled = config.Bind("Pillow", "SlomoEnabled", true, "Enable pillow slow motion effect"); PillowSlomoChance = config.Bind("Pillow", "SlomoChance", 0.2f, "Chance for pillow to trigger slow motion"); PillowSlomoDuration = config.Bind("Pillow", "SlomoDuration", 8f, "Duration of pillow slow motion effect"); DangerCloseMinCount = config.Bind("DangerClose", "MinCount", 1, "Minimum danger close rounds"); DangerCloseMaxCount = config.Bind("DangerClose", "MaxCount", 5, "Maximum danger close rounds"); EnableTwitchChatSosigs = config.Bind("ChatSosigs", "Enabled", true, "Enable Chat Sosig spawning system"); EnableSteamFriends = config.Bind("SteamFriends", "Enabled", true, "Enable Steam Friends integration for sosig spawning"); SteamFriendsRandomNames = config.Bind("SteamFriends", "UseRandomNames", false, "Use random friend from list instead of specific name"); SteamFriendsRefreshInterval = config.Bind("SteamFriends", "RefreshInterval", 300f, "Auto-refresh Steam friends list interval (seconds)"); EnableInfiniteTokens = config.Bind("TakeAndHold", "InfiniteTokens", false, "Enable infinite tokens in Take and Hold mode"); DisableEncryptionNodes = config.Bind("TakeAndHold", "DisableEncryptionNodes", false, "Disable encryption nodes in Take and Hold mode for easier gameplay"); DisableAllEncryptions = config.Bind("TakeAndHold.Encryption", "DisableAllEncryptions", false, "Master switch: Disable ALL encryption nodes (overrides specific settings)"); DisableEncryptionType1 = config.Bind("TakeAndHold.Encryption", "DisableType1", false, "Disable Type 1 encryption nodes (pattern matching)"); DisableEncryptionType2 = config.Bind("TakeAndHold.Encryption", "DisableType2", false, "Disable Type 2 encryption nodes (sequence)"); DisableEncryptionType3 = config.Bind("TakeAndHold.Encryption", "DisableType3", false, "Disable Type 3 encryption nodes (timed)"); AutoCompleteEncryption = config.Bind("TakeAndHold.Encryption", "AutoComplete", false, "Automatically complete enabled encryption nodes after delay"); EncryptionCompletionDelay = config.Bind("TakeAndHold.Encryption", "CompletionDelay", 2f, "Delay in seconds before auto-completing encryption (if AutoComplete enabled)"); } private void InitializeKeyBindings() { //IL_03d0: Unknown result type (might be due to invalid IL or missing references) Dictionary> dictionary = new Dictionary> { { "SpawnWonderfulToy", new KeyValuePair((KeyCode)257, "Spawn Wonderful Toy") }, { "SpawnJeditToy", new KeyValuePair((KeyCode)258, "Spawn Jedit Toy") }, { "SpawnHydration", new KeyValuePair((KeyCode)259, "Spawn Hydration") }, { "SpawnPillow", new KeyValuePair((KeyCode)260, "Spawn Pillow") }, { "SpawnShuri", new KeyValuePair((KeyCode)261, "Spawn Shuriken") }, { "SpawnFlash", new KeyValuePair((KeyCode)262, "Spawn Flash") }, { "SpawnFlash2", new KeyValuePair((KeyCode)263, "Spawn Flash2") }, { "SpawnSkittySubGun", new KeyValuePair((KeyCode)264, "Spawn Random Gun (Small)") }, { "SpawnSkittyBigGun", new KeyValuePair((KeyCode)265, "Spawn Random Gun (Large)") }, { "SpawnNadeRain", new KeyValuePair((KeyCode)267, "Spawn Grenade Rain") }, { "DangerCloseBarrage", new KeyValuePair((KeyCode)268, "Danger Close Barrage") }, { "DestroyHeld", new KeyValuePair((KeyCode)269, "Destroy Held Item") }, { "DestroyQuickbelt", new KeyValuePair((KeyCode)270, "Drop Quickbelt Items") }, { "TriggerSlomo", new KeyValuePair((KeyCode)102, "Trigger Slow Motion") }, { "TriggerZeroG", new KeyValuePair((KeyCode)103, "Trigger Zero Gravity") }, { "ToggleFireMode", new KeyValuePair((KeyCode)116, "Toggle Fire Mode") }, { "BoostMalfunction", new KeyValuePair((KeyCode)121, "Boost Malfunction") }, { "ShowStats", new KeyValuePair((KeyCode)9, "Show Stats") }, { "SpawnChatSosigFriendly", new KeyValuePair((KeyCode)112, "Spawn Friendly Chat Sosig") }, { "SpawnChatSosigEnemy", new KeyValuePair((KeyCode)111, "Spawn Enemy Chat Sosig") }, { "CycleChatSosigArmor", new KeyValuePair((KeyCode)108, "Cycle Chat Sosig Armor") }, { "ClearChatSosigs", new KeyValuePair((KeyCode)127, "Clear All Chat Sosigs") }, { "ChatSosigStats", new KeyValuePair((KeyCode)277, "Show Chat Sosig Stats") }, { "SpawnBossWarlord", new KeyValuePair((KeyCode)98, "Spawn Warlord Boss (Giant)") }, { "ClearBosses", new KeyValuePair((KeyCode)8, "Clear All Bosses") }, { "SpawnSteamFriendAlly", new KeyValuePair((KeyCode)91, "Spawn Steam Friend as Ally") }, { "SpawnSteamFriendEnemy", new KeyValuePair((KeyCode)93, "Spawn Steam Friend as Enemy") }, { "SpawnAllSteamFriendsAlly", new KeyValuePair((KeyCode)288, "Spawn All Steam Friends as Allies") }, { "SpawnAllSteamFriendsEnemy", new KeyValuePair((KeyCode)289, "Spawn All Steam Friends as Enemies") }, { "RefreshSteamFriends", new KeyValuePair((KeyCode)290, "Refresh Steam Friends List") }, { "SteamFriendsStats", new KeyValuePair((KeyCode)278, "Show Steam Friends Stats") }, { "SpawnAirStrike", new KeyValuePair((KeyCode)291, "Spawn Air Strike Smoke Grenade") }, { "SpawnTitanMachine", new KeyValuePair((KeyCode)292, "Spawn Titan Machine (AI Enemy)") }, { "SpawnNuke", new KeyValuePair((KeyCode)110, "Spawn Nuke (Massive Explosion)") }, { "EmptyHeldGunChamber", new KeyValuePair((KeyCode)101, "Empty Held Gun Chamber") } }; foreach (KeyValuePair> item in dictionary) { KeyBindings[item.Key] = config.Bind("KeyBindings", "KeyBindFor" + item.Key, item.Value.Key, item.Value.Value); } } public void RefreshCachedValues() { cachedMaxSlomo = MaxSlomo.Value; cachedSlomoWaitTime = SlomoWaitTime.Value; cachedSlomoScaleSpeed = SlomoScaleSpeed.Value; cachedSlomoReturnSpeed = SlomoReturnSpeed.Value; cachedSlomoUseRamp = SlomoUseRampSpeed.Value; cachedSlomoRampCurve = SlomoRampCurve.Value; cachedSlomoRampDuration = SlomoRampDuration.Value; cachedSlomoReturnRampDuration = SlomoReturnRampDuration.Value; cachedSlomoAffectsAudio = SlomoAffectsAudio.Value; cachedSlomoAudioPitchScale = SlomoAudioPitchScale.Value; cachedSlomoAudioPreservePitch = SlomoAudioPreservePitch.Value; cachedSlomoAffectsAudioSpeed = SlomoAffectsAudioSpeed.Value; cachedSlomoAudioSpeedScale = SlomoAudioSpeedScale.Value; cachedSlomoAudioMode = SlomoAudioMode.Value; cachedEnableInfiniteTokens = EnableInfiniteTokens.Value; cachedDisableEncryptionNodes = DisableEncryptionNodes.Value; cachedDisableAllEncryptions = DisableAllEncryptions.Value; } } [BepInPlugin("com.MrBeam.h3tvr", "H3TVR", "1.1.4")] [BepInProcess("h3vr.exe")] public class H3TVRImproved : BaseUnityPlugin { private enum EncryptionType { Unknown, Pattern, Sequence, Timed } [CompilerGenerated] private sealed class d__104 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public TNH_HoldPointSystemNode encryptionNode; public float delay; public H3TVRImproved <>4__this; private Exception 5__1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__104(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; try { if ((Object)(object)encryptionNode != (Object)null && (Object)(object)((Component)encryptionNode).gameObject != (Object)null && ((Component)encryptionNode).gameObject.activeSelf) { <>4__this.CompleteEncryptionNode(encryptionNode); ((BaseUnityPlugin)<>4__this).Logger.LogDebug((object)$"[TNH] Auto-completed encryption after {delay}s delay"); } } catch (Exception ex) { 5__1 = ex; ((BaseUnityPlugin)<>4__this).Logger.LogDebug((object)("[TNH] Error auto-completing encryption: " + 5__1.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__92 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public H3TVRImproved <>4__this; private MethodInfo 5__1; private Exception 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__92(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: <>1__state = -1; ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Delayed armor system initialization completed"); <>2__current = (object)new WaitForSeconds(2f); <>1__state = 2; return true; case 2: <>1__state = -1; if ((Object)(object)<>4__this.advancedChatSpawner != (Object)null) { ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Retrying template cache build after H3VR initialization..."); 5__1 = ((object)<>4__this.advancedChatSpawner).GetType().GetMethod("BuildTemplateCache", BindingFlags.Instance | BindingFlags.NonPublic); if ((object)5__1 != null) { try { 5__1.Invoke(<>4__this.advancedChatSpawner, null); ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Template cache rebuild completed"); } catch (Exception ex) { 5__2 = ex; ((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)("Template cache rebuild warning: " + 5__2.Message)); } } 5__1 = null; } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const float SlowdownFactor = 0.001f; private const float SlowdownLength = 6f; private const float ZeroGWaitTime = 6f; private const float RealisticFallTime = 1f; private const float MalfunctionBoostDuration = 120f; private const float ForcedMalfunctionChance = 0.75f; private string slomoStatus = "Off"; private string zeroGStatus = "Off"; private bool malfunctionBoostActive; private float malfunctionBoostEndTime; private float slomoRampStartTime; private float slomoRampStartValue; private bool isRamping; private ConfigEntry maxSlomo; private ConfigEntry slomoWaitTime; private ConfigEntry slomoScaleSpeed; private ConfigEntry slomoReturnSpeed; private ConfigEntry slomoVRControllerEnabled; private ConfigEntry slomoVRButton; private ConfigEntry slomoAffectsMovement; private ConfigEntry slomoMovementScale; private ConfigEntry slomoUseRampSpeed; private ConfigEntry slomoRampCurve; private ConfigEntry slomoRampDuration; private ConfigEntry slomoReturnRampDuration; private ConfigEntry enableKillSlomo; private ConfigEntry slomoAffectsAudio; private ConfigEntry slomoAudioPitchScale; private ConfigEntry slomoAudioPreservePitch; private ConfigEntry slomoAffectsAudioSpeed; private ConfigEntry slomoAudioSpeedScale; private ConfigEntry slomoAudioMode; private ConfigEntry useItemManagerForGunRandomization; private ConfigEntry gunList; private ConfigEntry magazineList; private ConfigEntry shurikenScale; private ConfigEntry shurikenMinCount; private ConfigEntry shurikenMaxCount; private ConfigEntry pillowMinCount; private ConfigEntry pillowMaxCount; private ConfigEntry pillowGrenadeEnabled; private ConfigEntry pillowGrenadeChance; private ConfigEntry pillowGrenadeArmedChance; private ConfigEntry pillowZeroGravityEnabled; private ConfigEntry pillowZeroGravityChance; private ConfigEntry pillowZeroGravityDuration; private ConfigEntry pillowSlomoEnabled; private ConfigEntry pillowSlomoChance; private ConfigEntry pillowSlomoDuration; private ConfigEntry dangerCloseMinCount; private ConfigEntry dangerCloseMaxCount; private readonly Dictionary> keyBindings = new Dictionary>(); private ConfigEntry enableTwitchChatSosigs; private ConfigEntry maxChatSosigs; private ConfigEntry enableSteamFriends; private ConfigEntry steamFriendsRandomNames; private ConfigEntry steamFriendsRefreshInterval; private ConfigEntry enableInfiniteTokens; private ConfigEntry disableEncryptionNodes; private ConfigEntry disableAllEncryptions; private ConfigEntry disableEncryptionType1; private ConfigEntry disableEncryptionType2; private ConfigEntry disableEncryptionType3; private ConfigEntry autoCompleteEncryption; private ConfigEntry encryptionCompletionDelay; private SlomoMovementController slomoMovementController; private readonly Hooks hooks = new Hooks(); private InputHandler inputHandler; private SpawnManager spawnManager; private EffectsManager effectsManager; private WeaponManager weaponManager; private AudioManager audioManager; private AdvancedChatSosigSpawner advancedChatSpawner; private SosigArmorWristMenuIntegration sosigArmorWristMenu; private SteamFriendsIntegration steamFriendsIntegration; private SosigCustomizationUI sosigCustomizationUI; private AirdropManager airdropManager; private LioranBoardIntegration lioranBoardIntegration; private static Dictionary originalAudioSpeeds = new Dictionary(); public H3TVRImproved() { hooks.Hook(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading H3TVR Enhanced Edition (Standalone Mode)"); } private void Awake() { try { OptionalDependencyManager.Initialize(((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR Enhanced Edition (Standalone Mode) is loading..."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 1: Initializing configuration..."); InitializeConfiguration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 2: Initializing optional dependencies..."); InitializeOptionalDependencies(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3: Initializing components..."); InitializeComponents(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3.5: Initializing UI..."); InitializeUI(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3.6: Initializing Airdrop Manager..."); InitializeAirdropManager(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 4: Initializing Sosig Spawner..."); InitializeSosigSpawner(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 5: Initializing SpawnManager..."); if ((Object)(object)spawnManager != (Object)null && (Object)(object)advancedChatSpawner != (Object)null) { spawnManager.Initialize(this, ((BaseUnityPlugin)this).Logger, advancedChatSpawner, audioManager); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SpawnManager initialized successfully"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Cannot initialize SpawnManager - spawnManager: {(Object)(object)spawnManager != (Object)null}, advancedChatSpawner: {(Object)(object)advancedChatSpawner != (Object)null}"); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 6: Initializing Twitch integration..."); InitializeTwitchIntegration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 6.5: Initializing Steam Friends integration..."); InitializeSteamFriendsIntegration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 6.6: Initializing LioranBoard 2 integration..."); InitializeLioranBoardIntegration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 7: Initializing wrist menu..."); try { InitializeSosigArmorWristMenuIntegration(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Non-critical error in wrist menu integration: " + ex.Message)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR Enhanced Edition loaded successfully!"); ((BaseUnityPlugin)this).Logger.LogInfo((object)OptionalDependencyManager.GetDependencyStatusReport()); if (MeatyceiverIntegrationManager.IsIntegrationEnabled()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Meatyceiver 2 Integration: ACTIVE"); ((BaseUnityPlugin)this).Logger.LogInfo((object)MeatyceiverIntegrationManager.GetTransformationStats()); } if (enableTwitchChatSosigs != null && enableTwitchChatSosigs.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Chat Sosig System: ENABLED"); ((BaseUnityPlugin)this).Logger.LogInfo((object)" - Standalone mode (no Twitch integration)"); ((BaseUnityPlugin)this).Logger.LogInfo((object)" - Use keyboard: P (ally), O (enemy), Delete (clear)"); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Chat Sosig System: DISABLED"); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error during H3TVR initialization: " + ex2.Message)); ((BaseUnityPlugin)this).Logger.LogError((object)("Stack trace: " + ex2.StackTrace)); try { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Attempting fallback initialization..."); InitializeConfiguration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR running in fallback mode with basic functionality"); } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogError((object)("Critical error - H3TVR cannot initialize: " + ex3.Message)); } } } private void InitializeConfiguration() { maxSlomo = ((BaseUnityPlugin)this).Config.Bind("Slomo", "MaxSlowmoScale", 0.1f, "Maximum slomo scale (0.01 = 1% speed, 0.1 = 10% speed)"); slomoWaitTime = ((BaseUnityPlugin)this).Config.Bind("Slomo", "WaitTime", 2f, "Time to wait at max slomo before returning to normal speed"); slomoScaleSpeed = ((BaseUnityPlugin)this).Config.Bind("Slomo", "ScaleDownSpeed", 1f, "Speed at which time slows down (higher = faster transition)"); slomoReturnSpeed = ((BaseUnityPlugin)this).Config.Bind("Slomo", "ReturnSpeed", 0.33f, "Speed at which time returns to normal (higher = faster return)"); slomoVRControllerEnabled = ((BaseUnityPlugin)this).Config.Bind("Slomo", "VRControllerEnabled", true, "Enable VR controller button to trigger slomo"); slomoVRButton = ((BaseUnityPlugin)this).Config.Bind("Slomo", "VRButton", "LeftX", "VR button to trigger slomo"); slomoAffectsMovement = ((BaseUnityPlugin)this).Config.Bind("Slomo", "AffectsMovement", true, "Whether slomo affects player movement speed"); slomoMovementScale = ((BaseUnityPlugin)this).Config.Bind("Slomo", "MovementScale", 0.3f, "Movement speed multiplier during slomo"); slomoUseRampSpeed = ((BaseUnityPlugin)this).Config.Bind("Slomo.Ramp", "UseRampSpeed", true, "Enable smooth ramp speed transitions for slomo (more cinematic)"); slomoRampCurve = ((BaseUnityPlugin)this).Config.Bind("Slomo.Ramp", "RampCurve", "EaseInOut", "Curve type for slomo ramp: Linear, EaseIn, EaseOut, EaseInOut, Smooth, Cinematic"); slomoRampDuration = ((BaseUnityPlugin)this).Config.Bind("Slomo.Ramp", "RampDuration", 0.5f, "Duration in seconds for slomo to ramp down to max slow speed"); slomoReturnRampDuration = ((BaseUnityPlugin)this).Config.Bind("Slomo.Ramp", "ReturnRampDuration", 0.8f, "Duration in seconds for slomo to ramp back to normal speed"); enableKillSlomo = ((BaseUnityPlugin)this).Config.Bind("Slomo", "EnableKillSlomo", true, "Enable slow motion effect on enemy kill."); slomoAffectsAudio = ((BaseUnityPlugin)this).Config.Bind("Audio", "SlomoAffectsAudio", true, "Whether slomo affects audio pitch"); slomoAudioPitchScale = ((BaseUnityPlugin)this).Config.Bind("Audio", "SlomoAudioPitchScale", 1f, "Audio pitch multiplier during slomo (1.0 = normal pitch, 0.5 = half pitch)"); slomoAudioPreservePitch = ((BaseUnityPlugin)this).Config.Bind("Audio", "SlomoPreservePitch", false, "If true, audio pitch is preserved (no pitch change). If false, uses pitch scaling."); slomoAffectsAudioSpeed = ((BaseUnityPlugin)this).Config.Bind("Audio", "SlomoAffectsAudioSpeed", false, "Whether slomo affects audio speed (time stretching)"); slomoAudioSpeedScale = ((BaseUnityPlugin)this).Config.Bind("Audio", "SlomoAudioSpeedScale", 1f, "Audio speed multiplier during slomo (1.0 = normal speed, 0.5 = half speed)"); slomoAudioMode = ((BaseUnityPlugin)this).Config.Bind("Audio", "SlomoAudioMode", "Both", "Audio adjustment mode during slomo: 'PitchOnly', 'SpeedOnly', 'Both', 'Independent'"); useItemManagerForGunRandomization = ((BaseUnityPlugin)this).Config.Bind("GunRandomization", "UseItemManager", true, "Use ItemManager for gun randomization (includes all H3VR and modded guns). If false, uses GunList/MagazineList config files."); gunList = ((BaseUnityPlugin)this).Config.Bind("General", "GunList", "DefaultGunList", "List of guns"); magazineList = ((BaseUnityPlugin)this).Config.Bind("General", "MagazineList", "DefaultMagazineList", "List of magazines"); InitializeSpawnConfigurations(); InitializeKeyBindings(); } private void InitializeSpawnConfigurations() { shurikenScale = ((BaseUnityPlugin)this).Config.Bind("Shuriken", "Scale", 1f, "Scale multiplier for spawned shuriken"); shurikenMinCount = ((BaseUnityPlugin)this).Config.Bind("Shuriken", "MinCount", 1, "Minimum number of shuriken to spawn"); shurikenMaxCount = ((BaseUnityPlugin)this).Config.Bind("Shuriken", "MaxCount", 3, "Maximum number of shuriken to spawn"); pillowMinCount = ((BaseUnityPlugin)this).Config.Bind("Pillow", "MinCount", 1, "Minimum number of pillows to spawn"); pillowMaxCount = ((BaseUnityPlugin)this).Config.Bind("Pillow", "MaxCount", 3, "Maximum number of pillows to spawn"); pillowGrenadeEnabled = ((BaseUnityPlugin)this).Config.Bind("Pillow", "GrenadeEnabled", true, "Enable pillow grenade effect"); pillowGrenadeChance = ((BaseUnityPlugin)this).Config.Bind("Pillow", "GrenadeChance", 0.1f, "Chance for pillow to spawn grenade"); pillowGrenadeArmedChance = ((BaseUnityPlugin)this).Config.Bind("Pillow", "GrenadeArmedChance", 0.3f, "Chance for pillow grenade to be armed"); pillowZeroGravityEnabled = ((BaseUnityPlugin)this).Config.Bind("Pillow", "ZeroGEnabled", true, "Enable pillow zero gravity effect"); pillowZeroGravityChance = ((BaseUnityPlugin)this).Config.Bind("Pillow", "ZeroGChance", 0.15f, "Chance for pillow to trigger zero gravity"); pillowZeroGravityDuration = ((BaseUnityPlugin)this).Config.Bind("Pillow", "ZeroGDuration", 10f, "Duration of pillow zero gravity effect"); pillowSlomoEnabled = ((BaseUnityPlugin)this).Config.Bind("Pillow", "SlomoEnabled", true, "Enable pillow slow motion effect"); pillowSlomoChance = ((BaseUnityPlugin)this).Config.Bind("Pillow", "SlomoChance", 0.2f, "Chance for pillow to trigger slow motion"); pillowSlomoDuration = ((BaseUnityPlugin)this).Config.Bind("Pillow", "SlomoDuration", 8f, "Duration of pillow slow motion effect"); dangerCloseMinCount = ((BaseUnityPlugin)this).Config.Bind("DangerClose", "MinCount", 1, "Minimum danger close rounds"); dangerCloseMaxCount = ((BaseUnityPlugin)this).Config.Bind("DangerClose", "MaxCount", 5, "Maximum danger close rounds"); enableTwitchChatSosigs = ((BaseUnityPlugin)this).Config.Bind("ChatSosigs", "Enabled", true, "Enable Chat Sosig spawning system"); maxChatSosigs = ((BaseUnityPlugin)this).Config.Bind("ChatSosigs", "MaxChatSosigs", 10, "Maximum number of active chat sosigs"); enableSteamFriends = ((BaseUnityPlugin)this).Config.Bind("SteamFriends", "Enabled", true, "Enable Steam Friends integration for sosig spawning"); steamFriendsRandomNames = ((BaseUnityPlugin)this).Config.Bind("SteamFriends", "UseRandomNames", false, "Use random friend from list instead of specific name"); steamFriendsRefreshInterval = ((BaseUnityPlugin)this).Config.Bind("SteamFriends", "RefreshInterval", 300f, "Auto-refresh Steam friends list interval (seconds)"); enableInfiniteTokens = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold", "InfiniteTokens", false, "Enable infinite tokens in Take and Hold mode"); disableEncryptionNodes = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold", "DisableEncryptionNodes", false, "Disable encryption nodes in Take and Hold mode for easier gameplay"); disableAllEncryptions = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold.Encryption", "DisableAllEncryptions", false, "Master switch: Disable ALL encryption nodes (overrides specific settings)"); disableEncryptionType1 = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold.Encryption", "DisableType1", false, "Disable Type 1 encryption nodes (pattern matching)"); disableEncryptionType2 = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold.Encryption", "DisableType2", false, "Disable Type 2 encryption nodes (sequence)"); disableEncryptionType3 = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold.Encryption", "DisableType3", false, "Disable Type 3 encryption nodes (timed)"); autoCompleteEncryption = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold.Encryption", "AutoComplete", false, "Automatically complete enabled encryption nodes after delay"); encryptionCompletionDelay = ((BaseUnityPlugin)this).Config.Bind("TakeAndHold.Encryption", "CompletionDelay", 2f, "Delay in seconds before auto-completing encryption (if AutoComplete enabled)"); } private void InitializeKeyBindings() { //IL_047b: Unknown result type (might be due to invalid IL or missing references) Dictionary> dictionary = new Dictionary> { { "SpawnWonderfulToy", new KeyValuePair((KeyCode)257, "Spawn Wonderful Toy") }, { "SpawnJeditToy", new KeyValuePair((KeyCode)258, "Spawn Jedit Toy") }, { "SpawnHydration", new KeyValuePair((KeyCode)259, "Spawn Hydration") }, { "SpawnPillow", new KeyValuePair((KeyCode)260, "Spawn Pillow") }, { "SpawnShuri", new KeyValuePair((KeyCode)261, "Spawn Shuriken") }, { "SpawnFlash", new KeyValuePair((KeyCode)262, "Spawn Flash") }, { "SpawnFlash2", new KeyValuePair((KeyCode)263, "Spawn Flash2") }, { "SpawnSkittySubGun", new KeyValuePair((KeyCode)264, "Spawn Random Gun (Small)") }, { "SpawnSkittyBigGun", new KeyValuePair((KeyCode)265, "Spawn Random Gun (Large)") }, { "SpawnNadeRain", new KeyValuePair((KeyCode)267, "Spawn Grenade Rain") }, { "DangerCloseBarrage", new KeyValuePair((KeyCode)268, "Danger Close Barrage") }, { "DestroyHeld", new KeyValuePair((KeyCode)269, "Destroy Held Item") }, { "DestroyQuickbelt", new KeyValuePair((KeyCode)270, "Drop Quickbelt Items") }, { "TriggerSlomo", new KeyValuePair((KeyCode)102, "Trigger Slow Motion") }, { "TriggerZeroG", new KeyValuePair((KeyCode)103, "Trigger Zero Gravity") }, { "ToggleFireMode", new KeyValuePair((KeyCode)116, "Toggle Fire Mode") }, { "BoostMalfunction", new KeyValuePair((KeyCode)121, "Boost Malfunction") }, { "ShowStats", new KeyValuePair((KeyCode)9, "Show Stats") }, { "SpawnChatSosigFriendly", new KeyValuePair((KeyCode)112, "Spawn Friendly Chat Sosig") }, { "SpawnChatSosigEnemy", new KeyValuePair((KeyCode)111, "Spawn Enemy Chat Sosig") }, { "CycleChatSosigArmor", new KeyValuePair((KeyCode)108, "Cycle Chat Sosig Armor") }, { "ClearChatSosigs", new KeyValuePair((KeyCode)127, "Clear All Chat Sosigs") }, { "ChatSosigStats", new KeyValuePair((KeyCode)277, "Show Chat Sosig Stats") }, { "ArmorGUI", new KeyValuePair((KeyCode)287, "Open Armor Configuration GUI") }, { "SpawnBossRandom", new KeyValuePair((KeyCode)98, "Spawn Random Boss") }, { "SpawnBossTank", new KeyValuePair((KeyCode)49, "Spawn Tank Boss") }, { "SpawnBossBerserker", new KeyValuePair((KeyCode)50, "Spawn Berserker Boss") }, { "SpawnBossSniper", new KeyValuePair((KeyCode)51, "Spawn Sniper Boss") }, { "SpawnBossSummoner", new KeyValuePair((KeyCode)52, "Spawn Summoner Boss") }, { "SpawnBossElite", new KeyValuePair((KeyCode)53, "Spawn Elite Boss") }, { "SpawnBossJuggernaut", new KeyValuePair((KeyCode)54, "Spawn Juggernaut Boss") }, { "SpawnBossAssassin", new KeyValuePair((KeyCode)55, "Spawn Assassin Boss") }, { "SpawnBossCommander", new KeyValuePair((KeyCode)56, "Spawn Commander Boss") }, { "ClearBosses", new KeyValuePair((KeyCode)8, "Clear All Bosses") }, { "SpawnSteamFriendAlly", new KeyValuePair((KeyCode)91, "Spawn Steam Friend as Ally") }, { "SpawnSteamFriendEnemy", new KeyValuePair((KeyCode)93, "Spawn Steam Friend as Enemy") }, { "SpawnAllSteamFriendsAlly", new KeyValuePair((KeyCode)288, "Spawn All Steam Friends as Allies") }, { "SpawnAllSteamFriendsEnemy", new KeyValuePair((KeyCode)289, "Spawn All Steam Friends as Enemies") }, { "RefreshSteamFriends", new KeyValuePair((KeyCode)290, "Refresh Steam Friends List") }, { "SteamFriendsStats", new KeyValuePair((KeyCode)278, "Show Steam Friends Stats") }, { "SpawnAirStrike", new KeyValuePair((KeyCode)291, "Spawn Air Strike Smoke Grenade") }, { "SpawnTitanMachine", new KeyValuePair((KeyCode)292, "Spawn Titan Machine (AI Enemy)") } }; foreach (KeyValuePair> item in dictionary) { keyBindings[item.Key] = ((BaseUnityPlugin)this).Config.Bind("KeyBindings", "KeyBindFor" + item.Key, item.Value.Key, item.Value.Value); } } private void InitializeOptionalDependencies() { try { OptionalDependencyManager.Initialize(((BaseUnityPlugin)this).Logger); MeatyceiverIntegrationManager.Initialize(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); StovepipeIntegrationManager.Initialize(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); AdvancedAIConfig.ApplyConfig(((BaseUnityPlugin)this).Config); BossConfig.ApplyConfig(((BaseUnityPlugin)this).Config); if (OptionalDependencyManager.HasAnyDependencies()) { int availableDependencyCount = OptionalDependencyManager.GetAvailableDependencyCount(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[H3TVRImproved] Enhanced functionality active with {availableDependencyCount} optional dependencies"); if (OptionalDependencyManager.IsStovepipeAvailable) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[H3TVRImproved] Stovepipe integration active - realistic weapon malfunctions enabled"); } if (OptionalDependencyManager.IsMeatyceiver2Available) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[H3TVRImproved] Meatyceiver 2 integration active - weapon transformations enabled"); } } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[H3TVRImproved] Running in standard mode - no optional dependencies found"); } if (AdvancedSosigAI.EnableAdvancedAI) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[H3TVRImproved] Advanced AI system enabled"); } if (BossSosigSystem.EnableBossSosigs) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[H3TVRImproved] Boss Sosig system enabled (Max: {BossSosigSystem.MaxBossesPerSession})"); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[H3TVRImproved] Error initializing optional dependencies: " + ex.Message)); } } private void InitializeAirdropManager() { airdropManager = ((Component)this).gameObject.AddComponent(); airdropManager.Initialize(this, ((BaseUnityPlugin)this).Logger); } private void InitializeUI() { sosigCustomizationUI = ((Component)this).gameObject.AddComponent(); sosigCustomizationUI.Initialize(((BaseUnityPlugin)this).Config); } private void InitializeComponents() { try { slomoMovementController = ((Component)this).gameObject.AddComponent(); slomoMovementController.Initialize(slomoMovementScale.Value, slomoAffectsMovement.Value, ((BaseUnityPlugin)this).Logger); inputHandler = ((Component)this).gameObject.AddComponent(); spawnManager = ((Component)this).gameObject.AddComponent(); effectsManager = ((Component)this).gameObject.AddComponent(); weaponManager = ((Component)this).gameObject.AddComponent(); audioManager = ((Component)this).gameObject.AddComponent(); audioManager.Initialize(this, ((BaseUnityPlugin)this).Logger); inputHandler.Initialize(keyBindings, this); effectsManager.Initialize(this, slomoMovementController, ((BaseUnityPlugin)this).Logger); weaponManager.Initialize(this, ((BaseUnityPlugin)this).Logger, audioManager); ((BaseUnityPlugin)this).Logger.LogInfo((object)"All components initialized successfully"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error initializing components: " + ex.Message)); ((BaseUnityPlugin)this).Logger.LogError((object)("Stack trace: " + ex.StackTrace)); } } private void InitializeSosigSpawner() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown try { GameObject val = new GameObject("AdvancedChatSosigSpawner"); val.transform.SetParent(((Component)this).transform); advancedChatSpawner = val.AddComponent(); advancedChatSpawner.Initialize(this, ((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Advanced Chat Sosig Spawner initialized with Update 120 TNH system (standalone mode)!"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error initializing Sosig Spawner: " + ex.Message)); } } private void InitializeTwitchIntegration() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Twitch integration disabled - AdvancedChatSosigSpawner runs in standalone mode"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Use keyboard controls: P = spawn ally, O = spawn enemy, Delete = clear all"); } private void InitializeSteamFriendsIntegration() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if (!enableSteamFriends.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Steam Friends integration disabled in config"); return; } try { GameObject val = new GameObject("SteamFriendsIntegration"); val.transform.SetParent(((Component)this).transform); steamFriendsIntegration = val.AddComponent(); if ((Object)(object)advancedChatSpawner != (Object)null) { steamFriendsIntegration.Initialize(this, advancedChatSpawner, ((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Steam Friends integration initialized successfully"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Steam Friends controls: [ = spawn ally, ] = spawn enemy, F7 = spawn all as allies, F8 = spawn all as enemies"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Cannot initialize Steam Friends - Advanced Chat Spawner not ready"); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to initialize Steam Friends integration: " + ex.Message)); steamFriendsIntegration = null; } } private void InitializeLioranBoardIntegration() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown try { GameObject val = new GameObject("LioranBoardIntegration"); val.transform.SetParent(((Component)this).transform); lioranBoardIntegration = val.AddComponent(); lioranBoardIntegration.Initialize(((BaseUnityPlugin)this).Logger, this); ((BaseUnityPlugin)this).Logger.LogInfo((object)"LioranBoard 2 integration initialized successfully."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to initialize LioranBoard 2 integration: " + ex.Message)); } } private void InitializeSosigArmorWristMenuIntegration() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown try { GameObject val = new GameObject("SosigArmorWristMenuIntegration"); val.transform.SetParent(((Component)this).transform); sosigArmorWristMenu = val.AddComponent(); sosigArmorWristMenu.Initialize(this, null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Sosig Armor Wrist Menu Integration initialized successfully"); ((MonoBehaviour)this).StartCoroutine(DelayedArmorSystemInitialization()); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to initialize Sosig Armor Wrist Menu Integration: " + ex.Message)); } } private IEnumerator DelayedArmorSystemInitialization() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__92(0) { <>4__this = this }; } public void Update() { HandleSlomoStateMachine(); HandleZeroGravityStateMachine(); HandleMalfunctionBoost(); HandleInfiniteTokens(); weaponManager?.UpdateScaleModifiers(); } private void OnDestroy() { lioranBoardIntegration?.Shutdown(); } private void HandleSlomoStateMachine() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) try { switch (slomoStatus) { case "Slowing": ((BaseUnityPlugin)this).Logger.LogInfo((object)"Slowing!"); effectsManager.SlomoScaleDown(); break; case "Wait": ((BaseUnityPlugin)this).Logger.LogInfo((object)"Waiting!"); slomoStatus = "Paused"; try { audioManager?.PlaySlomoSound("active"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Audio error during slomo: " + ex.Message)); } ((MonoBehaviour)this).StartCoroutine(effectsManager.SlomoWait(delegate { slomoStatus = "Return"; })); break; case "Return": ((BaseUnityPlugin)this).Logger.LogInfo((object)"Returning!"); effectsManager.SlomoReturn(); break; } if (Time.timeScale == 1f) { if (slomoStatus != "Off") { try { audioManager?.PlaySlomoSound("end"); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Audio error ending slomo: " + ex2.Message)); } } slomoStatus = "Off"; } slomoMovementController?.UpdateMovementScale(Time.timeScale); } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error in slomo state machine: " + ex3.Message)); slomoStatus = "Off"; } } private void HandleZeroGravityStateMachine() { if (zeroGStatus == "On") { ((MonoBehaviour)this).StartCoroutine(effectsManager.ZeroGWait(delegate { zeroGStatus = "Falling"; effectsManager.RealisticFall(); })); } if (zeroGStatus == "Falling") { ((MonoBehaviour)this).StartCoroutine(effectsManager.RealisticFallWait(delegate { effectsManager.ZeroGravityBumpUp(); zeroGStatus = "Off"; })); } } private void HandleMalfunctionBoost() { if (malfunctionBoostActive) { if (Time.time >= malfunctionBoostEndTime) { malfunctionBoostActive = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Meatyceiver malfunction boost ended."); } else { weaponManager.ApplyMalfunctionLogic(); } } } private void HandleInfiniteTokens() { if (!enableInfiniteTokens.Value && !disableEncryptionNodes.Value && !disableAllEncryptions.Value) { return; } try { if ((Object)(object)GM.TNH_Manager != (Object)null && (Object)(object)GM.TNH_Manager.m_curHoldPoint != (Object)null) { if (enableInfiniteTokens.Value) { GM.TNH_Manager.m_numTokens = 999; } if (disableAllEncryptions.Value || disableEncryptionNodes.Value) { DisableEncryptionNodes(); } else if (disableEncryptionType1.Value || disableEncryptionType2.Value || disableEncryptionType3.Value) { DisableSpecificEncryptionNodes(); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error in HandleInfiniteTokens: " + ex.Message)); } } private void DisableEncryptionNodes() { try { if ((Object)(object)GM.TNH_Manager == (Object)null || (Object)(object)GM.TNH_Manager.m_curHoldPoint == (Object)null) { return; } TNH_HoldPoint curHoldPoint = GM.TNH_Manager.m_curHoldPoint; if ((Object)(object)curHoldPoint.m_systemNode != (Object)null && !curHoldPoint.m_systemNode.m_hasActivated) { if (autoCompleteEncryption.Value) { ((MonoBehaviour)this).StartCoroutine(AutoCompleteEncryptionDelayed(curHoldPoint.m_systemNode, encryptionCompletionDelay.Value)); ((BaseUnityPlugin)this).Logger.LogDebug((object)$"[TNH] Auto-completing all encryptions after {encryptionCompletionDelay.Value}s delay"); } else { CompleteEncryptionNode(curHoldPoint.m_systemNode); ((BaseUnityPlugin)this).Logger.LogDebug((object)"[TNH] Disabled all encryption nodes"); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error disabling encryption nodes: " + ex.Message)); } } private void DisableSpecificEncryptionNodes() { try { if ((Object)(object)GM.TNH_Manager == (Object)null || (Object)(object)GM.TNH_Manager.m_curHoldPoint == (Object)null) { return; } TNH_HoldPoint curHoldPoint = GM.TNH_Manager.m_curHoldPoint; if (!((Object)(object)curHoldPoint.m_systemNode != (Object)null) || curHoldPoint.m_systemNode.m_hasActivated) { return; } TNH_HoldPointSystemNode systemNode = curHoldPoint.m_systemNode; EncryptionType encryptionType = DetectEncryptionType(systemNode); bool flag = false; string text = ""; switch (encryptionType) { case EncryptionType.Pattern: if (disableEncryptionType1.Value) { flag = true; text = "Pattern"; } break; case EncryptionType.Sequence: if (disableEncryptionType2.Value) { flag = true; text = "Sequence"; } break; case EncryptionType.Timed: if (disableEncryptionType3.Value) { flag = true; text = "Timed"; } break; case EncryptionType.Unknown: if (disableEncryptionType1.Value || disableEncryptionType2.Value || disableEncryptionType3.Value) { flag = true; text = "Unknown"; } break; } if (flag) { if (autoCompleteEncryption.Value) { ((MonoBehaviour)this).StartCoroutine(AutoCompleteEncryptionDelayed(systemNode, encryptionCompletionDelay.Value)); ((BaseUnityPlugin)this).Logger.LogDebug((object)$"[TNH] Auto-completing {text} encryption after {encryptionCompletionDelay.Value}s delay"); } else { CompleteEncryptionNode(systemNode); ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Disabled " + text + " encryption")); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error disabling specific encryption: " + ex.Message)); } } private EncryptionType DetectEncryptionType(TNH_HoldPointSystemNode encryptionNode) { try { if ((Object)(object)encryptionNode == (Object)null) { return EncryptionType.Unknown; } return EncryptionType.Unknown; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error detecting encryption type: " + ex.Message)); return EncryptionType.Unknown; } } private void CompleteEncryptionNode(TNH_HoldPointSystemNode encryptionNode) { try { if (!((Object)(object)encryptionNode == (Object)null) && (Object)(object)((Component)encryptionNode).gameObject != (Object)null) { ((Component)encryptionNode).gameObject.SetActive(false); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error completing encryption node: " + ex.Message)); } } private IEnumerator AutoCompleteEncryptionDelayed(TNH_HoldPointSystemNode encryptionNode, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__104(0) { <>4__this = this, encryptionNode = encryptionNode, delay = delay }; } public void TriggerSlomo() { //IL_003c: 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) slomoStatus = "Slowing"; slomoRampStartTime = Time.unscaledTime; slomoRampStartValue = Time.timeScale; isRamping = true; audioManager?.PlaySlomoSound(); } public void TriggerZeroGravity() { effectsManager.ZeroGravityBumpDown(); } public void ActivateMalfunctionBoost() { weaponManager.ActivateMalfunctionBoost(ref malfunctionBoostActive, ref malfunctionBoostEndTime); } public SpawnManager GetSpawnManager() { return spawnManager; } public WeaponManager GetWeaponManager() { return weaponManager; } public EffectsManager GetEffectsManager() { return effectsManager; } public AudioManager GetAudioManager() { return audioManager; } public AirdropManager GetAirdropManager() { return airdropManager; } public void GetShurikenConfig(out int min, out int max) { min = shurikenMinCount.Value; max = shurikenMaxCount.Value; } public float GetShurikenScale() { return shurikenScale.Value; } public void GetPillowConfig(out int min, out int max) { min = pillowMinCount.Value; max = pillowMaxCount.Value; } public void GetDangerCloseConfig(out int min, out int max) { min = dangerCloseMinCount.Value; max = dangerCloseMaxCount.Value; } public void GetPillowGrenadeConfig(out bool enabled, out float chance, out float armedChance) { enabled = pillowGrenadeEnabled.Value; chance = pillowGrenadeChance.Value; armedChance = pillowGrenadeArmedChance.Value; } public void GetPillowZeroGravityConfig(out bool enabled, out float chance, out float duration) { enabled = pillowZeroGravityEnabled.Value; chance = pillowZeroGravityChance.Value; duration = pillowZeroGravityDuration.Value; } public void GetPillowSlomoConfig(out bool enabled, out float chance, out float duration) { enabled = pillowSlomoEnabled.Value; chance = pillowSlomoChance.Value; duration = pillowSlomoDuration.Value; } public bool UseItemManagerForGuns() { return useItemManagerForGunRandomization.Value; } public bool IsKillSlomoEnabled() { return enableKillSlomo.Value; } public void GetGunLists(out string gunListValue, out string magListValue) { gunListValue = gunList.Value; magListValue = magazineList.Value; } public void GetSlomoConfig(out float maxSlomoValue, out float waitTime, out float scaleSpeed, out float returnSpeed) { maxSlomoValue = maxSlomo.Value; waitTime = slomoWaitTime.Value; scaleSpeed = slomoScaleSpeed.Value; returnSpeed = slomoReturnSpeed.Value; } public void GetSlomoRampConfig(out bool useRamp, out string curve, out float rampDuration, out float returnDuration) { useRamp = slomoUseRampSpeed.Value; curve = slomoRampCurve.Value; rampDuration = slomoRampDuration.Value; returnDuration = slomoReturnRampDuration.Value; } public void GetSlomoAudioConfig(out bool affectsAudio, out float pitchScale, out bool preservePitch) { affectsAudio = slomoAffectsAudio.Value; pitchScale = slomoAudioPitchScale.Value; preservePitch = slomoAudioPreservePitch.Value; } public void GetSlomoAudioConfigComplete(out bool affectsAudio, out float pitchScale, out bool preservePitch, out bool affectsSpeed, out float speedScale, out string mode) { affectsAudio = slomoAffectsAudio.Value; pitchScale = slomoAudioPitchScale.Value; preservePitch = slomoAudioPreservePitch.Value; affectsSpeed = slomoAffectsAudioSpeed.Value; speedScale = slomoAudioSpeedScale.Value; mode = slomoAudioMode.Value; } public void GetSlomoMovementConfig(out bool affectsMovement, out float movementScale) { affectsMovement = slomoAffectsMovement.Value; movementScale = slomoMovementScale.Value; } public void UpdateSlomoMovementSettings() { slomoMovementController?.UpdateSettings(slomoMovementScale.Value, slomoAffectsMovement.Value); } public void SetSlomoStatus(string status) { slomoStatus = status; } public SosigArmorWristMenuIntegration GetSosigArmorWristMenu() { return sosigArmorWristMenu; } public AdvancedChatSosigSpawner GetAdvancedChatSpawner() { return advancedChatSpawner; } public SteamFriendsIntegration GetSteamFriendsIntegration() { return steamFriendsIntegration; } public bool IsSteamFriendsEnabled() { return enableSteamFriends != null && enableSteamFriends.Value; } public bool UseSteamFriendsRandomNames() { return steamFriendsRandomNames != null && steamFriendsRandomNames.Value; } public float GetSteamFriendsRefreshInterval() { return (steamFriendsRefreshInterval != null) ? steamFriendsRefreshInterval.Value : 300f; } public bool IsInfiniteTokensEnabled() { return enableInfiniteTokens != null && enableInfiniteTokens.Value; } public bool IsEncryptionDisabled() { return disableEncryptionNodes != null && disableEncryptionNodes.Value; } public void SetInfiniteTokens(bool enabled) { if (enableInfiniteTokens != null) { enableInfiniteTokens.Value = enabled; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Infinite tokens " + (enabled ? "enabled" : "disabled"))); } } public void SetEncryptionNodes(bool disabled) { if (disableEncryptionNodes != null) { disableEncryptionNodes.Value = disabled; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Encryption nodes " + (disabled ? "disabled" : "enabled"))); } } public void GetSlomoVRConfig(out bool vrEnabled, out string vrButton) { vrEnabled = slomoVRControllerEnabled.Value; vrButton = slomoVRButton.Value; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] public static void FixPitch(AudioSource __instance, ref float value) { H3TVRImproved h3TVRImproved = Object.FindObjectOfType(); if ((Object)(object)h3TVRImproved == (Object)null) { return; } if (Time.timeScale >= 0.99f && Time.timeScale <= 1.01f) { if (originalAudioSpeeds.ContainsKey(__instance)) { originalAudioSpeeds.Remove(__instance); } return; } h3TVRImproved.GetSlomoAudioConfigComplete(out bool affectsAudio, out float pitchScale, out bool preservePitch, out bool affectsSpeed, out float speedScale, out string mode); if (!affectsAudio) { return; } if (!originalAudioSpeeds.ContainsKey(__instance)) { originalAudioSpeeds[__instance] = 1f; } switch (mode.ToLower()) { case "pitchonly": ApplyPitchAdjustment(ref value, preservePitch, pitchScale); break; case "speedonly": ApplySpeedAdjustment(__instance, speedScale); value = 1f; break; case "both": ApplyPitchAdjustment(ref value, preservePitch, pitchScale); if (affectsSpeed) { ApplySpeedAdjustment(__instance, speedScale); } break; case "independent": ApplyPitchAdjustment(ref value, preservePitch, pitchScale); if (affectsSpeed) { ApplySpeedAdjustment(__instance, speedScale); } break; default: ApplyPitchAdjustment(ref value, preservePitch, pitchScale); if (affectsSpeed) { ApplySpeedAdjustment(__instance, speedScale); } break; } value = Mathf.Clamp(value, 0.1f, 3f); } private static void ApplyPitchAdjustment(ref float pitch, bool preservePitch, float pitchScale) { if (preservePitch) { pitch *= 1f / Time.timeScale; return; } float num = pitch * (Time.timeScale * pitchScale); pitch = Mathf.Clamp(num, 0.1f, 3f); } private static void ApplySpeedAdjustment(AudioSource source, float speedScale) { if ((Object)(object)source == (Object)null || (Object)(object)source.clip == (Object)null) { return; } try { float num = Time.timeScale * speedScale; num = Mathf.Clamp(num, 0.1f, 3f); if (source.isPlaying && num < 0.95f) { float num2 = source.time / source.clip.length; int num3 = Mathf.RoundToInt((float)source.timeSamples * num); if (Mathf.Abs(num3 - source.timeSamples) > 100) { source.timeSamples = Mathf.Clamp(num3, 0, source.clip.samples - 1); } } } catch (Exception ex) { Debug.LogError((object)("Error applying speed adjustment: " + ex.Message)); } } } internal static class PluginInfo { internal const string NAME = "H3TVR"; internal const string GUID = "com.MrBeam.h3tvr"; internal const string VERSION = "1.1.4"; } public class LioranBoardIntegration : MonoBehaviour { [CompilerGenerated] private sealed class d__16 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public LioranBoardIntegration <>4__this; private FileInfo 5__1; private FileInfo 5__2; private Exception 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__16(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; 5__2 = null; 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (File.Exists(<>4__this.allyIniFilePath)) { <>4__this.lastAllyIniWriteTime = new FileInfo(<>4__this.allyIniFilePath).LastWriteTime; } if (File.Exists(<>4__this.enemyIniFilePath)) { <>4__this.lastEnemyIniWriteTime = new FileInfo(<>4__this.enemyIniFilePath).LastWriteTime; } break; case 1: <>1__state = -1; try { if (File.Exists(<>4__this.allyIniFilePath)) { 5__1 = new FileInfo(<>4__this.allyIniFilePath); if (5__1.LastWriteTime != <>4__this.lastAllyIniWriteTime) { <>4__this.ProcessLioranBoardFile(<>4__this.allyIniFilePath, isAlly: true); 5__1.Refresh(); <>4__this.lastAllyIniWriteTime = 5__1.LastWriteTime; } 5__1 = null; } if (File.Exists(<>4__this.enemyIniFilePath)) { 5__2 = new FileInfo(<>4__this.enemyIniFilePath); if (5__2.LastWriteTime != <>4__this.lastEnemyIniWriteTime) { <>4__this.ProcessLioranBoardFile(<>4__this.enemyIniFilePath, isAlly: false); 5__2.Refresh(); <>4__this.lastEnemyIniWriteTime = 5__2.LastWriteTime; } 5__2 = null; } } catch (Exception ex) { 5__3 = ex; <>4__this.logger.LogError((object)("Error watching file: " + 5__3.Message + "\n" + 5__3.StackTrace)); } break; } if (<>4__this.isWatching) { <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private ManualLogSource logger; private string configFilePath; private H3TVRImproved plugin; private bool isWatching = false; private const string DEFAULT_LIORANBOARD_PATH = "C:\\LioranBoard"; private const string ALLY_FILENAME = "ally"; private const string ENEMY_FILENAME = "enemy"; private string allyIniFilePath; private string enemyIniFilePath; private DateTime lastAllyIniWriteTime = DateTime.MinValue; private DateTime lastEnemyIniWriteTime = DateTime.MinValue; private string allyChatFilePath; private string enemyChatFilePath; public void Initialize(ManualLogSource logSource, H3TVRImproved pluginInstance) { logger = logSource; plugin = pluginInstance; configFilePath = Path.Combine(Paths.BepInExRootPath, "H3TVR_LioranBoard_Config.ini"); string text = LoadOrCreateConfig(); allyIniFilePath = Path.Combine(text, "ally"); enemyIniFilePath = Path.Combine(text, "enemy"); allyChatFilePath = Path.Combine(Path.Combine(Paths.BepInExRootPath, "config"), "H3TVR_AllyChat.txt"); enemyChatFilePath = Path.Combine(Path.Combine(Paths.BepInExRootPath, "config"), "H3TVR_EnemyChat.txt"); logger.LogInfo((object)"=== LioranBoard 2.0 Integration (ChatWatcher Unified) ==="); logger.LogInfo((object)("LioranBoard folder: " + text)); logger.LogInfo((object)("Watching ally INI: " + allyIniFilePath)); logger.LogInfo((object)("Watching enemy INI: " + enemyIniFilePath)); logger.LogInfo((object)("Writing to ChatWatcher ally: " + allyChatFilePath)); logger.LogInfo((object)("Writing to ChatWatcher enemy: " + enemyChatFilePath)); logger.LogInfo((object)"All spawns routed through ChatWatcher for unified handling."); EnsureDirectoriesExist(text); isWatching = true; ((MonoBehaviour)this).StartCoroutine(WatchFileCoroutine()); } private void EnsureDirectoriesExist(string lioranBoardFolder) { try { if (!Directory.Exists(lioranBoardFolder)) { Directory.CreateDirectory(lioranBoardFolder); logger.LogInfo((object)("Created LioranBoard folder: " + lioranBoardFolder)); } string directoryName = Path.GetDirectoryName(allyChatFilePath); if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); logger.LogInfo((object)("Created ChatWatcher config folder: " + directoryName)); } } catch (Exception ex) { logger.LogError((object)("Failed to create directories: " + ex.Message)); } } private string LoadOrCreateConfig() { try { if (File.Exists(configFilePath)) { string[] array = File.ReadAllLines(configFilePath); string[] array2 = array; foreach (string text in array2) { if (text.StartsWith("LioranBoardFolder=")) { string text2 = text.Substring("LioranBoardFolder=".Length).Trim(); if (!string.IsNullOrEmpty(text2)) { logger.LogInfo((object)("Using LioranBoard folder from config: " + text2)); return text2; } } } } } catch (Exception ex) { logger.LogWarning((object)("Error reading config: " + ex.Message)); } try { string contents = "; H3TVR LioranBoard 2.0 Integration Config\r\n; \r\n; Set the path to your LioranBoard folder below.\r\n; This is where LioranBoard creates the 'ally' and 'enemy' files.\r\n; \r\nLioranBoardFolder=C:\\LioranBoard\r\n; \r\n; === LIORANBOARD 2.0 SETUP ===\r\n; \r\n; For ALLY spawns, use File: Save Text with:\r\n; file name: ally\r\n; section: ally\r\n; key: username (or any key name)\r\n; text: /$user_name$/\r\n; \r\n; For ENEMY spawns, use File: Save Text with:\r\n; file name: enemy\r\n; section: enemy\r\n; key: username (or any key name)\r\n; text: /$user_name$/\r\n; \r\n; Works with both Channel Points AND Chat Commands!\r\n"; File.WriteAllText(configFilePath, contents); logger.LogInfo((object)("Created config file: " + configFilePath)); } catch (Exception ex2) { logger.LogError((object)("Failed to create config: " + ex2.Message)); } return "C:\\LioranBoard"; } private IEnumerator WatchFileCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__16(0) { <>4__this = this }; } private void ProcessLioranBoardFile(string filePath, bool isAlly) { try { string[] array = File.ReadAllLines(filePath); List list = new List(); bool flag = false; string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (!string.IsNullOrEmpty(text2) && !text2.StartsWith(";") && !text2.StartsWith("[") && text2.Contains("=")) { int num = text2.IndexOf('='); string text3 = text2.Substring(num + 1).Trim(); if (!string.IsNullOrEmpty(text3)) { list.Add(text3); flag = true; } } } foreach (string item in list) { string path = (isAlly ? allyChatFilePath : enemyChatFilePath); string text4 = (isAlly ? "ally" : "enemy"); File.AppendAllText(path, item + Environment.NewLine); logger.LogInfo((object)("[LioranBoard -> ChatWatcher] " + text4 + ": '" + item + "'")); } if (flag) { string text5 = (isAlly ? "ally" : "enemy"); File.WriteAllText(filePath, "[" + text5 + "]\r\nusername=\r\n"); } } catch (Exception ex) { logger.LogError((object)("Error processing LioranBoard file: " + ex.Message)); } } public void Shutdown() { isWatching = false; ((MonoBehaviour)this).StopAllCoroutines(); } private void OnDestroy() { Shutdown(); plugin = null; logger = null; } } public static class MeatyceiverIntegrationManager { public enum WeaponQuality { Common, Uncommon, Rare, Epic, Legendary, Artifact } private static ManualLogSource logger; private static bool initialized = false; private static Type meatyceiverType; private static object meatyceiverInstance; private static MethodInfo transformMethod; private static MethodInfo checkCompatibilityMethod; private static MethodInfo isTransformedMethod; private static MethodInfo getQualityMethod; private static MethodInfo setQualityMethod; private static PropertyInfo transformChanceProperty; private static FieldInfo enabledField; private static ConfigFile config; private static Dictionary> chanceConfigs; private static Dictionary> featureConfigs; private static Dictionary> multiplierConfigs; private static Dictionary> intConfigs; private static readonly Dictionary transformationCache = new Dictionary(); private static readonly Dictionary transformationTimes = new Dictionary(); private static readonly Dictionary transformationCooldowns = new Dictionary(); private static readonly Dictionary weaponQualities = new Dictionary(); private static DateTime lastCacheClear = DateTime.Now; private const string MEATYCEIVER2_GUID = "Potatoes.Meatyceiver_2"; private const string MEATYCEIVER_LEGACY_GUID = "potatoes1286.meatyceiver"; private const string MEATYCEIVER_ALPHA_GUID = "potatoes.meatyceiver.alpha"; public static bool IsMeatyceiver2Available { get; private set; } = false; public static string DetectedVersion { get; private set; } = "Unknown"; public static string DetectedApiVersion { get; private set; } = "Unknown"; public static int TotalTransformationAttempts { get; private set; } = 0; public static int SuccessfulTransformations { get; private set; } = 0; public static int CachedResults { get; private set; } = 0; public static int CooldownBlocked { get; private set; } = 0; public static int QualityPreserved { get; private set; } = 0; public static Dictionary TransformationsByContext { get; private set; } = new Dictionary(); public static Dictionary TransformationsByWeaponType { get; private set; } = new Dictionary(); public static void Initialize(ManualLogSource logSource, ConfigFile configFile) { if (!initialized) { logger = logSource; config = configFile; logger.LogInfo((object)"[MeatyceiverIntegration] Initializing Meatyceiver 2 integration..."); InitializeConfiguration(); DetectMeatyceiver2(); if (IsMeatyceiver2Available) { CacheMeatyceiverMethods(); InitializeCompatibilityLayer(); logger.LogInfo((object)("[MeatyceiverIntegration] Successfully initialized with Meatyceiver 2 " + DetectedVersion + " (API: " + DetectedApiVersion + ")")); } else { logger.LogInfo((object)"[MeatyceiverIntegration] Meatyceiver 2 not detected - integration disabled"); } initialized = true; } } private static void InitializeConfiguration() { chanceConfigs = new Dictionary>(); featureConfigs = new Dictionary>(); multiplierConfigs = new Dictionary>(); intConfigs = new Dictionary>(); chanceConfigs["Normal"] = config.Bind("Meatyceiver 2", "ChanceNormal", 0.02f, "Normal transformation chance"); chanceConfigs["Elite"] = config.Bind("Meatyceiver 2", "ChanceElite", 0.01f, "Elite sosig transformation chance"); chanceConfigs["Chaos"] = config.Bind("Meatyceiver 2", "ChanceChaos", 0.15f, "Chaos mode transformation chance"); chanceConfigs["Player"] = config.Bind("Meatyceiver 2", "ChancePlayer", 0.05f, "Player weapon transformation chance"); chanceConfigs["SosigWeapon"] = config.Bind("Meatyceiver 2", "ChanceSosigWeapon", 0.03f, "Sosig weapon transformation chance"); chanceConfigs["EnemyWeapon"] = config.Bind("Meatyceiver 2", "ChanceEnemyWeapon", 0.04f, "Enemy weapon transformation chance"); chanceConfigs["AllyWeapon"] = config.Bind("Meatyceiver 2", "ChanceAllyWeapon", 0.02f, "Ally weapon transformation chance"); chanceConfigs["BossWeapon"] = config.Bind("Meatyceiver 2", "ChanceBossWeapon", 0.001f, "Boss weapon transformation chance"); chanceConfigs["RareWeapon"] = config.Bind("Meatyceiver 2", "ChanceRareWeapon", 0.005f, "Rare weapon transformation chance"); chanceConfigs["LegendaryWeapon"] = config.Bind("Meatyceiver 2", "ChanceLegendaryWeapon", 0.001f, "Legendary weapon transformation chance"); multiplierConfigs["Pistol"] = config.Bind("Meatyceiver 2", "PistolMultiplier", 1.2f, "Pistol transformation multiplier"); multiplierConfigs["Rifle"] = config.Bind("Meatyceiver 2", "RifleMultiplier", 1f, "Rifle transformation multiplier"); multiplierConfigs["Shotgun"] = config.Bind("Meatyceiver 2", "ShotgunMultiplier", 0.8f, "Shotgun transformation multiplier"); multiplierConfigs["SMG"] = config.Bind("Meatyceiver 2", "SMGMultiplier", 1.5f, "SMG transformation multiplier"); multiplierConfigs["Sniper"] = config.Bind("Meatyceiver 2", "SniperMultiplier", 0.5f, "Sniper transformation multiplier"); multiplierConfigs["LMG"] = config.Bind("Meatyceiver 2", "LMGMultiplier", 0.7f, "LMG transformation multiplier"); multiplierConfigs["AssaultRifle"] = config.Bind("Meatyceiver 2", "AssaultRifleMultiplier", 0.9f, "Assault rifle transformation multiplier"); multiplierConfigs["CommonQuality"] = config.Bind("Meatyceiver 2", "CommonQualityMultiplier", 1f, "Common quality transformation multiplier"); multiplierConfigs["UncommonQuality"] = config.Bind("Meatyceiver 2", "UncommonQualityMultiplier", 0.8f, "Uncommon quality transformation multiplier"); multiplierConfigs["RareQuality"] = config.Bind("Meatyceiver 2", "RareQualityMultiplier", 0.6f, "Rare quality transformation multiplier"); multiplierConfigs["EpicQuality"] = config.Bind("Meatyceiver 2", "EpicQualityMultiplier", 0.4f, "Epic quality transformation multiplier"); multiplierConfigs["LegendaryQuality"] = config.Bind("Meatyceiver 2", "LegendaryQualityMultiplier", 0.2f, "Legendary quality transformation multiplier"); multiplierConfigs["ArtifactQuality"] = config.Bind("Meatyceiver 2", "ArtifactQualityMultiplier", 0.1f, "Artifact quality transformation multiplier"); featureConfigs["Enabled"] = config.Bind("Meatyceiver 2", "Enabled", true, "Enable Meatyceiver 2 integration"); featureConfigs["ForceTransformOnChaos"] = config.Bind("Meatyceiver 2", "ForceTransformOnChaos", false, "Force transformation in chaos mode"); featureConfigs["AllowMultipleTransforms"] = config.Bind("Meatyceiver 2", "AllowMultipleTransforms", false, "Allow multiple transformations"); featureConfigs["PreserveAmmo"] = config.Bind("Meatyceiver 2", "PreserveAmmo", true, "Preserve ammo during transformation"); featureConfigs["PreserveAttachments"] = config.Bind("Meatyceiver 2", "PreserveAttachments", true, "Preserve attachments during transformation"); featureConfigs["PreserveQuality"] = config.Bind("Meatyceiver 2", "PreserveQuality", true, "Preserve weapon quality during transformation"); featureConfigs["PlayTransformSound"] = config.Bind("Meatyceiver 2", "PlayTransformSound", true, "Play transformation sound effects"); featureConfigs["ShowTransformParticles"] = config.Bind("Meatyceiver 2", "ShowTransformParticles", true, "Show transformation particle effects"); featureConfigs["EnableCaching"] = config.Bind("Meatyceiver 2", "EnableCaching", true, "Enable transformation result caching"); featureConfigs["EnableCooldowns"] = config.Bind("Meatyceiver 2", "EnableCooldowns", true, "Enable transformation cooldowns"); featureConfigs["RespectOriginalChances"] = config.Bind("Meatyceiver 2", "RespectOriginalChances", true, "Respect Meatyceiver 2's original chances"); featureConfigs["UseContextualLogic"] = config.Bind("Meatyceiver 2", "UseContextualLogic", true, "Use H3TVR contextual logic"); featureConfigs["UseQualityBasedChances"] = config.Bind("Meatyceiver 2", "UseQualityBasedChances", true, "Use weapon quality to modify transformation chances"); featureConfigs["EnableBatchTransformation"] = config.Bind("Meatyceiver 2", "EnableBatchTransformation", true, "Enable batch transformation support"); featureConfigs["DebugMode"] = config.Bind("Meatyceiver 2", "DebugMode", false, "Enable debug mode"); featureConfigs["VerboseLogging"] = config.Bind("Meatyceiver 2", "VerboseLogging", false, "Enable verbose logging"); intConfigs["CooldownSeconds"] = config.Bind("Meatyceiver 2", "CooldownSeconds", 30, "Cooldown between transformations (seconds)"); intConfigs["CacheLifetimeMinutes"] = config.Bind("Meatyceiver 2", "CacheLifetimeMinutes", 10, "Cache entry lifetime in minutes"); intConfigs["MaxCacheSize"] = config.Bind("Meatyceiver 2", "MaxCacheSize", 1000, "Maximum number of cached entries"); intConfigs["BatchSize"] = config.Bind("Meatyceiver 2", "BatchSize", 10, "Maximum weapons to transform in a single batch"); } private static void DetectMeatyceiver2() { try { Dictionary pluginInfos = Chainloader.PluginInfos; if (pluginInfos.ContainsKey("Potatoes.Meatyceiver_2")) { IsMeatyceiver2Available = true; DetectedVersion = pluginInfos["Potatoes.Meatyceiver_2"].Metadata.Version.ToString(); logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver 2 detected via BepInEx: v" + DetectedVersion)); } else if (pluginInfos.ContainsKey("potatoes1286.meatyceiver")) { IsMeatyceiver2Available = true; DetectedVersion = pluginInfos["potatoes1286.meatyceiver"].Metadata.Version.ToString(); logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver detected via legacy GUID: v" + DetectedVersion)); } else if (pluginInfos.ContainsKey("potatoes.meatyceiver.alpha")) { IsMeatyceiver2Available = true; DetectedVersion = pluginInfos["potatoes.meatyceiver.alpha"].Metadata.Version.ToString(); logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver Alpha detected via GUID: v" + DetectedVersion)); } else { DetectViaReflection(); } } catch (Exception ex) { logger.LogError((object)("[MeatyceiverIntegration] Error during Meatyceiver 2 detection: " + ex.Message)); IsMeatyceiver2Available = false; } } private static void DetectViaReflection() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { Type[] types = assembly.GetTypes(); Type[] array2 = types; foreach (Type type in array2) { if (IsMeatyceiverType(type)) { meatyceiverType = type; IsMeatyceiver2Available = true; DetectedVersion = assembly.GetName().Version?.ToString() ?? "Unknown"; logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver detected via reflection: " + type.FullName)); return; } } } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not scan assembly " + assembly.FullName + ": " + ex.Message)); } } } private static bool IsMeatyceiverType(Type type) { if ((object)type == null) { return false; } string text = type.Name.ToLower(); string text2 = type.Namespace?.ToLower() ?? ""; return text.Contains("meatyceiver") || text.Contains("meatyreceiver") || text.Contains("meattransform") || text2.Contains("meatyceiver") || text2.Contains("potatoes") || (text.Contains("meat") && (text.Contains("weapon") || text.Contains("transform"))); } private static void CacheMeatyceiverMethods() { if ((object)meatyceiverType == null) { return; } try { FieldInfo field = meatyceiverType.GetField("Instance", BindingFlags.Static | BindingFlags.Public); if ((object)field == null) { field = meatyceiverType.GetField("instance", BindingFlags.Static | BindingFlags.Public); } if ((object)field != null) { meatyceiverInstance = field.GetValue(null); logger.LogDebug((object)"[MeatyceiverIntegration] Found Meatyceiver instance"); } MethodInfo[] methods = meatyceiverType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { string text = methodInfo.Name.ToLower(); if ((text.Contains("transform") || text.Contains("meat")) && !text.Contains("check") && !text.Contains("is")) { transformMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached transform method: " + methodInfo.Name)); } else if (text.Contains("check") || text.Contains("compatible") || text.Contains("can")) { checkCompatibilityMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached compatibility method: " + methodInfo.Name)); } else if (text.Contains("is") && (text.Contains("transform") || text.Contains("meat"))) { isTransformedMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached is-transformed method: " + methodInfo.Name)); } else if (text.Contains("quality") && text.Contains("get")) { getQualityMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached get quality method: " + methodInfo.Name)); } else if (text.Contains("quality") && text.Contains("set")) { setQualityMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached set quality method: " + methodInfo.Name)); } } PropertyInfo[] properties = meatyceiverType.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); PropertyInfo[] array2 = properties; foreach (PropertyInfo propertyInfo in array2) { string text2 = propertyInfo.Name.ToLower(); if (text2.Contains("chance") || text2.Contains("probability")) { transformChanceProperty = propertyInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached chance property: " + propertyInfo.Name)); } } FieldInfo[] fields = meatyceiverType.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); FieldInfo[] array3 = fields; foreach (FieldInfo fieldInfo in array3) { string text3 = fieldInfo.Name.ToLower(); if (text3.Contains("enabled") || text3.Contains("active")) { enabledField = fieldInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached enabled field: " + fieldInfo.Name)); } } } catch (Exception ex) { logger.LogWarning((object)("[MeatyceiverIntegration] Error caching Meatyceiver methods: " + ex.Message)); } } private static void InitializeCompatibilityLayer() { try { if ((object)getQualityMethod != null && (object)setQualityMethod != null) { DetectedApiVersion = "2.0+"; logger.LogDebug((object)"[MeatyceiverIntegration] Detected advanced API with quality support"); } else if ((object)transformMethod != null) { DetectedApiVersion = "1.5+"; logger.LogDebug((object)"[MeatyceiverIntegration] Detected basic transformation API"); } else { DetectedApiVersion = "1.0"; logger.LogWarning((object)"[MeatyceiverIntegration] Limited API detected - some features may not work"); } } catch (Exception ex) { logger.LogWarning((object)("[MeatyceiverIntegration] Error initializing compatibility layer: " + ex.Message)); DetectedApiVersion = "Unknown"; } } public static bool TryTransformWeapon(FVRFireArm firearm, string context = "Normal", float customChance = -1f, bool forceTransform = false) { //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) if (!IsIntegrationEnabled() || (Object)(object)firearm == (Object)null) { return false; } TotalTransformationAttempts++; try { string weaponKey = GetWeaponKey(firearm); if (featureConfigs["EnableCooldowns"].Value && IsOnCooldown(weaponKey) && !forceTransform) { CooldownBlocked++; if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)("[MeatyceiverIntegration] Transformation blocked by cooldown for " + weaponKey)); } return false; } if (featureConfigs["EnableCaching"].Value && transformationCache.ContainsKey(weaponKey)) { CachedResults++; bool flag = transformationCache[weaponKey]; if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)$"[MeatyceiverIntegration] Using cached result for {weaponKey}: {flag}"); } return flag; } if (!CanWeaponBeTransformed(firearm) && !forceTransform) { CacheResult(weaponKey, result: false); return false; } float num = ((customChance >= 0f) ? customChance : CalculateTransformationChance(firearm, context)); if (!forceTransform && Random.value > num) { if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)$"[MeatyceiverIntegration] Transformation chance failed: {num:P2}"); } CacheResult(weaponKey, result: false); return false; } bool flag2 = PerformTransformation(firearm, context); if (flag2) { SuccessfulTransformations++; UpdateTransformationStatistics(context, firearm); if (featureConfigs["EnableCooldowns"].Value) { SetCooldown(weaponKey); } logger.LogInfo((object)("[MeatyceiverIntegration] Successfully transformed " + ((Object)firearm).name + " (context: " + context + ")")); if (featureConfigs["PlayTransformSound"].Value) { PlayTransformationSound(((Component)firearm).transform.position); } if (featureConfigs["ShowTransformParticles"].Value) { ShowTransformationParticles(((Component)firearm).transform.position); } } CacheResult(weaponKey, flag2); return flag2; } catch (Exception ex) { logger.LogError((object)("[MeatyceiverIntegration] Error during weapon transformation: " + ex.Message)); return false; } } public static Dictionary TryTransformWeaponsBatch(List firearms, string context = "Normal", float customChance = -1f, bool forceTransform = false) { Dictionary dictionary = new Dictionary(); if (!IsIntegrationEnabled() || !featureConfigs["EnableBatchTransformation"].Value) { foreach (FVRFireArm firearm in firearms) { dictionary[firearm] = false; } return dictionary; } int batchSize = intConfigs["BatchSize"].Value; List> list = (from x in firearms.Select((FVRFireArm x, int i) => new { Index = i, Value = x }) group x by x.Index / batchSize into x select x.Select(v => v.Value).ToList()).ToList(); foreach (List item in list) { foreach (FVRFireArm item2 in item) { dictionary[item2] = TryTransformWeapon(item2, context, customChance, forceTransform); } } logger.LogDebug((object)$"[MeatyceiverIntegration] Batch transformation completed: {dictionary.Count((KeyValuePair r) => r.Value)}/{dictionary.Count} successful"); return dictionary; } public static bool CanWeaponBeTransformed(FVRFireArm firearm) { if (!IsIntegrationEnabled() || (Object)(object)firearm == (Object)null) { return false; } try { if ((object)checkCompatibilityMethod != null) { return (bool)checkCompatibilityMethod.Invoke(meatyceiverInstance, new object[1] { firearm }); } if (IsWeaponAlreadyTransformed(firearm)) { return featureConfigs["AllowMultipleTransforms"].Value; } string text = ((Object)firearm).name.ToLower(); return !text.Contains("meat") && !text.Contains("flesh") && !text.Contains("organic") && !text.Contains("bio"); } catch (Exception ex) { logger.LogError((object)("[MeatyceiverIntegration] Error checking weapon compatibility: " + ex.Message)); return false; } } public static bool IsWeaponAlreadyTransformed(FVRFireArm firearm) { if ((Object)(object)firearm == (Object)null) { return false; } try { if ((object)isTransformedMethod != null) { return (bool)isTransformedMethod.Invoke(meatyceiverInstance, new object[1] { firearm }); } string text = ((Object)firearm).name.ToLower(); return text.Contains("meat") || text.Contains("flesh") || text.Contains("organic"); } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Error checking transformation status: " + ex.Message)); return false; } } public static WeaponQuality GetWeaponQuality(FVRFireArm firearm) { if ((Object)(object)firearm == (Object)null) { return WeaponQuality.Common; } try { string weaponKey = GetWeaponKey(firearm); if (weaponQualities.ContainsKey(weaponKey)) { return weaponQualities[weaponKey]; } if ((object)getQualityMethod != null && getQualityMethod.Invoke(meatyceiverInstance, new object[1] { firearm }) is int val) { WeaponQuality weaponQuality = (WeaponQuality)Math.Min(val, 5); weaponQualities[weaponKey] = weaponQuality; return weaponQuality; } WeaponQuality weaponQuality2 = DetectWeaponQualityFallback(firearm); weaponQualities[weaponKey] = weaponQuality2; return weaponQuality2; } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Error getting weapon quality: " + ex.Message)); return WeaponQuality.Common; } } public static string GetTransformationStats() { float num = ((TotalTransformationAttempts > 0) ? ((float)SuccessfulTransformations / (float)TotalTransformationAttempts * 100f) : 0f); string text = string.Join(", ", TransformationsByContext.Select, string>((KeyValuePair kvp) => $"{kvp.Key}: {kvp.Value}").ToArray()); string text2 = string.Join(", ", TransformationsByWeaponType.Select, string>((KeyValuePair kvp) => $"{kvp.Key}: {kvp.Value}").ToArray()); return "Meatyceiver 2 Integration Stats:\n• Status: " + (IsMeatyceiver2Available ? "✓ Active" : "✗ Not Available") + "\n• Version: " + DetectedVersion + " (API: " + DetectedApiVersion + ")\n" + $"• Attempts: {TotalTransformationAttempts}\n" + $"• Successes: {SuccessfulTransformations}\n" + $"• Success Rate: {num:F1}%\n" + $"• Cached Results: {CachedResults}\n" + $"• Cooldown Blocked: {CooldownBlocked}\n" + $"• Quality Preserved: {QualityPreserved}\n" + $"• Cache Size: {transformationCache.Count}\n" + "• By Context: " + text + "\n• By Weapon Type: " + text2; } public static void ClearCache() { transformationCache.Clear(); transformationTimes.Clear(); transformationCooldowns.Clear(); weaponQualities.Clear(); CachedResults = 0; logger.LogDebug((object)"[MeatyceiverIntegration] Cache cleared"); } public static bool IsIntegrationEnabled() { return IsMeatyceiver2Available && featureConfigs["Enabled"].Value; } public static string GetCompatibilityInfo() { if (!IsMeatyceiver2Available) { return "Meatyceiver 2 not detected"; } List list = new List(); if ((object)transformMethod != null) { list.Add("Basic Transformation"); } if ((object)checkCompatibilityMethod != null) { list.Add("Compatibility Checking"); } if ((object)isTransformedMethod != null) { list.Add("Transform Status Detection"); } if ((object)getQualityMethod != null) { list.Add("Quality Reading"); } if ((object)setQualityMethod != null) { list.Add("Quality Setting"); } return "Meatyceiver 2 Compatibility:\n• Version: " + DetectedVersion + "\n• API Version: " + DetectedApiVersion + "\n" + list.Count + "• Available Features: " + string.Join(", ", list.ToArray()) + "\n• Integration Status: " + (IsIntegrationEnabled() ? "Active" : "Disabled"); } public static bool GetFeatureConfig(string key) { if (!featureConfigs.ContainsKey(key)) { return false; } return featureConfigs[key].Value; } public static float GetChanceConfig(string key) { if (!chanceConfigs.ContainsKey(key)) { return 0.02f; } return chanceConfigs[key].Value; } public static float GetMultiplierConfig(string key) { if (!multiplierConfigs.ContainsKey(key)) { return 1f; } return multiplierConfigs[key].Value; } private static float CalculateTransformationChance(FVRFireArm firearm, string context) { float num = 0.02f; if (chanceConfigs.ContainsKey(context)) { num = chanceConfigs[context].Value; } else { context = context.ToLower(); num = (context.Contains("chaos") ? chanceConfigs["Chaos"].Value : ((context.Contains("elite") || context.Contains("boss")) ? chanceConfigs["Elite"].Value : (context.Contains("player") ? chanceConfigs["Player"].Value : (context.Contains("enemy") ? chanceConfigs["EnemyWeapon"].Value : ((!context.Contains("ally")) ? chanceConfigs["Normal"].Value : chanceConfigs["AllyWeapon"].Value))))); } float weaponCategoryMultiplier = GetWeaponCategoryMultiplier(firearm); float num2 = 1f; if (featureConfigs["UseQualityBasedChances"].Value) { num2 = GetQualityMultiplier(firearm); } float num3 = num * weaponCategoryMultiplier * num2; if (featureConfigs["RespectOriginalChances"].Value && (object)transformChanceProperty != null) { try { float val = (float)transformChanceProperty.GetValue(meatyceiverInstance, null); num3 = Math.Min(num3, val); } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not get original chance: " + ex.Message)); } } if (featureConfigs["DebugMode"].Value) { logger.LogDebug((object)$"[MeatyceiverIntegration] Calculated chance for {((Object)firearm).name} ({context}): {num3:P2} (base: {num:P2}, category: {weaponCategoryMultiplier:F2}, quality: {num2:F2})"); } return Mathf.Clamp01(num3); } private static float GetWeaponCategoryMultiplier(FVRFireArm firearm) { string text = ((Object)firearm).name.ToLower(); if (text.Contains("pistol") || text.Contains("handgun")) { return multiplierConfigs["Pistol"].Value; } if (text.Contains("shotgun")) { return multiplierConfigs["Shotgun"].Value; } if (text.Contains("smg") || text.Contains("submachine")) { return multiplierConfigs["SMG"].Value; } if (text.Contains("sniper") || text.Contains("precision")) { return multiplierConfigs["Sniper"].Value; } if (text.Contains("lmg") || text.Contains("machinegun")) { return multiplierConfigs["LMG"].Value; } if (text.Contains("assault") || text.Contains("carbine")) { return multiplierConfigs["AssaultRifle"].Value; } if (text.Contains("rifle")) { return multiplierConfigs["Rifle"].Value; } return 1f; } private static float GetQualityMultiplier(FVRFireArm firearm) { return GetWeaponQuality(firearm) switch { WeaponQuality.Common => multiplierConfigs["CommonQuality"].Value, WeaponQuality.Uncommon => multiplierConfigs["UncommonQuality"].Value, WeaponQuality.Rare => multiplierConfigs["RareQuality"].Value, WeaponQuality.Epic => multiplierConfigs["EpicQuality"].Value, WeaponQuality.Legendary => multiplierConfigs["LegendaryQuality"].Value, WeaponQuality.Artifact => multiplierConfigs["ArtifactQuality"].Value, _ => 1f, }; } private static WeaponQuality DetectWeaponQualityFallback(FVRFireArm firearm) { string text = ((Object)firearm).name.ToLower(); if (text.Contains("legendary") || text.Contains("mythic") || text.Contains("unique")) { return WeaponQuality.Legendary; } if (text.Contains("epic") || text.Contains("purple") || text.Contains("elite")) { return WeaponQuality.Epic; } if (text.Contains("rare") || text.Contains("blue") || text.Contains("special")) { return WeaponQuality.Rare; } if (text.Contains("uncommon") || text.Contains("green") || text.Contains("enhanced")) { return WeaponQuality.Uncommon; } return WeaponQuality.Common; } private static bool PerformTransformation(FVRFireArm firearm, string context) { if ((object)transformMethod == null) { logger.LogWarning((object)"[MeatyceiverIntegration] No transform method available"); return false; } try { int num = 0; WeaponQuality weaponQuality = WeaponQuality.Common; List list = new List(); if (featureConfigs["PreserveAmmo"].Value && (Object)(object)firearm.Magazine != (Object)null) { num = firearm.Magazine.m_numRounds; } if (featureConfigs["PreserveQuality"].Value) { weaponQuality = GetWeaponQuality(firearm); } if (featureConfigs["PreserveAttachments"].Value) { list.AddRange(((Component)firearm).GetComponentsInChildren()); } object obj = transformMethod.Invoke(meatyceiverInstance, new object[1] { firearm }); bool flag = !(obj is bool) || (bool)obj; if (flag) { if (featureConfigs["PreserveAmmo"].Value && (Object)(object)firearm.Magazine != (Object)null && num > 0) { firearm.Magazine.m_numRounds = num; } if (featureConfigs["PreserveQuality"].Value && (object)setQualityMethod != null && weaponQuality > WeaponQuality.Common) { try { setQualityMethod.Invoke(meatyceiverInstance, new object[2] { firearm, (int)weaponQuality }); QualityPreserved++; } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not preserve quality: " + ex.Message)); } } } return flag; } catch (Exception ex2) { logger.LogError((object)("[MeatyceiverIntegration] Transformation failed: " + ex2.Message)); return false; } } private static bool IsOnCooldown(string weaponKey) { if (!transformationCooldowns.ContainsKey(weaponKey)) { return false; } DateTime dateTime = transformationCooldowns[weaponKey].AddSeconds(intConfigs["CooldownSeconds"].Value); return DateTime.Now < dateTime; } private static void SetCooldown(string weaponKey) { transformationCooldowns[weaponKey] = DateTime.Now; } private static void UpdateTransformationStatistics(string context, FVRFireArm firearm) { if (!TransformationsByContext.ContainsKey(context)) { TransformationsByContext[context] = 0; } TransformationsByContext[context]++; string weaponTypeName = GetWeaponTypeName(firearm); if (!TransformationsByWeaponType.ContainsKey(weaponTypeName)) { TransformationsByWeaponType[weaponTypeName] = 0; } TransformationsByWeaponType[weaponTypeName]++; } private static string GetWeaponTypeName(FVRFireArm firearm) { string text = ((Object)firearm).name.ToLower(); if (text.Contains("pistol") || text.Contains("handgun")) { return "Pistol"; } if (text.Contains("shotgun")) { return "Shotgun"; } if (text.Contains("smg") || text.Contains("submachine")) { return "SMG"; } if (text.Contains("sniper")) { return "Sniper"; } if (text.Contains("lmg")) { return "LMG"; } if (text.Contains("rifle")) { return "Rifle"; } return "Unknown"; } private static void PlayTransformationSound(Vector3 position) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) try { AudioManager audioManager = Object.FindObjectOfType(); if ((Object)(object)audioManager != (Object)null) { audioManager.PlayWeaponSpawnSound("transformation", position); } else { logger.LogDebug((object)$"[MeatyceiverIntegration] Playing transformation sound at {position}"); } } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not play transformation sound: " + ex.Message)); } } private static void ShowTransformationParticles(Vector3 position) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) try { EffectsManager effectsManager = Object.FindObjectOfType(); if ((Object)(object)effectsManager != (Object)null) { logger.LogDebug((object)$"[MeatyceiverIntegration] Showing transformation particles at {position}"); } else { logger.LogDebug((object)$"[MeatyceiverIntegration] Showing transformation particles at {position}"); } } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not show transformation particles: " + ex.Message)); } } private static string GetWeaponKey(FVRFireArm firearm) { try { if (((FVRPhysicalObject)firearm).ObjectWrapper?.ItemID != null) { return ((FVRPhysicalObject)firearm).ObjectWrapper.ItemID; } return ((Object)((Component)firearm).gameObject).GetInstanceID().ToString(); } catch { return ((object)firearm).GetHashCode().ToString(); } } private static void CacheResult(string weaponKey, bool result) { if (featureConfigs["EnableCaching"].Value) { transformationCache[weaponKey] = result; transformationTimes[weaponKey] = DateTime.Now; if (transformationCache.Count > intConfigs["MaxCacheSize"].Value) { CleanOldCacheEntries(forceClear: true); } if ((DateTime.Now - lastCacheClear).TotalMinutes > 5.0) { CleanOldCacheEntries(); lastCacheClear = DateTime.Now; } } } private static void CleanOldCacheEntries(bool forceClear = false) { DateTime dateTime = DateTime.Now.AddMinutes(-intConfigs["CacheLifetimeMinutes"].Value); List list = new List(); foreach (KeyValuePair transformationTime in transformationTimes) { if (transformationTime.Value < dateTime || forceClear) { list.Add(transformationTime.Key); } } if (forceClear && list.Count < transformationCache.Count / 2) { IEnumerable> source = transformationTimes.OrderBy, DateTime>((KeyValuePair kvp) => kvp.Value).Take(transformationCache.Count / 2); list.AddRange(source.Select((KeyValuePair kvp) => kvp.Key)); } foreach (string item in list) { transformationCache.Remove(item); transformationTimes.Remove(item); weaponQualities.Remove(item); } if (list.Count > 0) { logger.LogDebug((object)$"[MeatyceiverIntegration] Cleaned {list.Count} cache entries"); } } } public class SosigArmorWristMenuIntegration : MonoBehaviour { [CompilerGenerated] private sealed class d__9 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SosigArmorWristMenuIntegration <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.SubscribeToEvents(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private SosigArmorWristMenuComplete wristMenu; private H3TVRImproved plugin; private bool isInitialized = false; public static SosigArmorWristMenuIntegration Instance { get; private set; } public void Initialize(H3TVRImproved pluginInstance, object wristMenuInstance) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if (!isInitialized) { Instance = this; plugin = pluginInstance; isInitialized = true; GameObject val = new GameObject("SosigArmorWristMenuComplete"); val.transform.SetParent(((Component)this).transform); wristMenu = val.AddComponent(); wristMenu.Initialize(plugin, wristMenuInstance); ((MonoBehaviour)this).StartCoroutine(DelayedEventSubscription()); Debug.Log((object)"[SosigArmorWristMenuIntegration] Integration initialized successfully with SosigArmorWristMenuComplete"); } } private void SubscribeToEvents() { Debug.Log((object)"[SosigArmorWristMenuIntegration] Subscribing to armor system events"); } private IEnumerator DelayedEventSubscription() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__9(0) { <>4__this = this }; } private void OnSosigSpawned(Sosig sosig, string userName, bool isFriendly) { if ((Object)(object)sosig == (Object)null || !isInitialized) { return; } try { ApplyArmorToSosig(sosig, isFriendly); Debug.Log((object)("[SosigArmorWristMenuIntegration] Applied armor to " + (isFriendly ? "friendly" : "enemy") + " sosig for user: " + userName)); } catch (Exception ex) { Debug.LogError((object)("[SosigArmorWristMenuIntegration] Failed to apply armor to sosig: " + ex.Message)); } } public bool IsFactionArmorEnabled() { if ((Object)(object)wristMenu == (Object)null) { return false; } return wristMenu.IsFactionArmorEnabled(); } public void ApplyArmorToSosig(Sosig sosig, bool isFriendly) { if (!((Object)(object)wristMenu == (Object)null) && !((Object)(object)sosig == (Object)null)) { wristMenu.ApplyArmorToSosig(sosig, isFriendly); } } public SosigArmorWristMenuComplete GetArmorMenu() { return wristMenu; } public bool IsInitialized() { return isInitialized && (Object)(object)wristMenu != (Object)null; } public void OpenArmorMenu() { if ((Object)(object)wristMenu != (Object)null) { wristMenu.ToggleMenu(); } else { Debug.LogWarning((object)"[SosigArmorWristMenuIntegration] Armor menu not initialized"); } } public void OnPluginArmorRequest(Sosig sosig, string userName, bool isFriendly) { if (!((Object)(object)sosig == (Object)null)) { ApplyArmorToSosig(sosig, isFriendly); } } public bool IsArmorIntegrationAvailable() { return isInitialized && (Object)(object)wristMenu != (Object)null; } public string GetArmorIntegrationStatus() { if (!isInitialized || (Object)(object)wristMenu == (Object)null) { return "Armor Integration: Not Available"; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("=== H3TVR Armor Integration Status ==="); stringBuilder.AppendLine($"Integration Active: {isInitialized}"); stringBuilder.AppendLine($"Armor Menu Available: {(Object)(object)wristMenu != (Object)null}"); stringBuilder.AppendLine($"Faction Armor: {IsFactionArmorEnabled()}"); stringBuilder.AppendLine("Current Preset: " + wristMenu.GetCurrentPresetInfo()); return stringBuilder.ToString(); } private void Start() { if (!isInitialized) { Debug.LogWarning((object)"[SosigArmorWristMenuIntegration] Starting without proper initialization"); } } private void OnDestroy() { Instance = null; Debug.Log((object)"[SosigArmorWristMenuIntegration] Integration destroyed"); } public void TestArmorIntegration() { Debug.Log((object)"[SosigArmorWristMenuIntegration] Armor integration test completed"); } public string GetDebugStatus() { return GetArmorIntegrationStatus(); } } public class SteamFriendsIntegration : MonoBehaviour { private ManualLogSource logger; private AdvancedChatSosigSpawner sosigSpawner; private H3TVRImproved plugin; private List friendNames = new List(); private List friendSteamIDs = new List(); private bool isInitialized = false; private bool steamAvailable = false; private float lastRefreshTime = 0f; private const float REFRESH_INTERVAL = 300f; public static SteamFriendsIntegration Instance { get; private set; } public void Initialize(H3TVRImproved pluginInstance, AdvancedChatSosigSpawner spawner, ManualLogSource logSource) { if ((Object)(object)Instance != (Object)null) { Object.Destroy((Object)(object)this); return; } Instance = this; plugin = pluginInstance; sosigSpawner = spawner; logger = logSource; try { steamAvailable = SteamManager.Initialized; if (!steamAvailable) { logger.LogWarning((object)"[SteamFriends] Steam is not initialized - friends integration disabled"); return; } logger.LogInfo((object)"[SteamFriends] Steam detected - loading friends list..."); RefreshFriendsList(); isInitialized = true; logger.LogInfo((object)$"[SteamFriends] Integration initialized successfully with {friendNames.Count} friends"); } catch (Exception ex) { logger.LogError((object)("[SteamFriends] Initialization failed: " + ex.Message)); steamAvailable = false; } } public void RefreshFriendsList() { //IL_0069: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (!steamAvailable) { logger.LogWarning((object)"[SteamFriends] Cannot refresh - Steam not available"); return; } try { friendNames.Clear(); friendSteamIDs.Clear(); int friendCount = SteamFriends.GetFriendCount((EFriendFlags)4); logger.LogInfo((object)$"[SteamFriends] Found {friendCount} Steam friends"); for (int i = 0; i < friendCount; i++) { CSteamID friendByIndex = SteamFriends.GetFriendByIndex(i, (EFriendFlags)4); string friendPersonaName = SteamFriends.GetFriendPersonaName(friendByIndex); if (!string.IsNullOrEmpty(friendPersonaName)) { friendNames.Add(friendPersonaName); friendSteamIDs.Add(friendByIndex); logger.LogDebug((object)("[SteamFriends] Added friend: " + friendPersonaName)); } } lastRefreshTime = Time.time; logger.LogInfo((object)$"[SteamFriends] Loaded {friendNames.Count} friend names"); } catch (Exception ex) { logger.LogError((object)("[SteamFriends] Failed to refresh friends list: " + ex.Message)); } } public string GetRandomFriendName() { if (!isInitialized || friendNames.Count == 0) { logger.LogWarning((object)"[SteamFriends] No friends available - using fallback"); return "Steam Friend"; } if (Time.time - lastRefreshTime > 300f) { logger.LogInfo((object)"[SteamFriends] Auto-refreshing friends list"); RefreshFriendsList(); } string text = friendNames[Random.Range(0, friendNames.Count)]; logger.LogDebug((object)("[SteamFriends] Selected random friend: " + text)); return text; } public string GetFriendName(int index) { if (!isInitialized || friendNames.Count == 0) { return "Steam Friend"; } if (index < 0 || index >= friendNames.Count) { logger.LogWarning((object)$"[SteamFriends] Invalid index {index} - using random"); return GetRandomFriendName(); } return friendNames[index]; } public List GetAllFriendNames() { return new List(friendNames); } public bool IsFriendOnline(int index) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_003f: Invalid comparison between Unknown and I4 if (!steamAvailable || index < 0 || index >= friendSteamIDs.Count) { return false; } try { EPersonaState friendPersonaState = SteamFriends.GetFriendPersonaState(friendSteamIDs[index]); return (int)friendPersonaState > 0; } catch { return false; } } public int GetFriendCount() { return friendNames.Count; } public bool IsAvailable() { return isInitialized && steamAvailable && friendNames.Count > 0; } public void SpawnSosigWithFriendName(bool isAlly) { if (!IsAvailable()) { logger.LogWarning((object)"[SteamFriends] Cannot spawn - integration not available"); return; } string randomFriendName = GetRandomFriendName(); if (isAlly) { sosigSpawner.SpawningSequence(randomFriendName); logger.LogInfo((object)("[SteamFriends] Spawned ally sosig with friend name: " + randomFriendName)); } else { sosigSpawner.SpawningSequenceEnemy(1, randomFriendName); logger.LogInfo((object)("[SteamFriends] Spawned enemy sosig with friend name: " + randomFriendName)); } } public void SpawnMultipleSosigsWithFriendNames(int count, bool isAlly) { if (!IsAvailable()) { logger.LogWarning((object)"[SteamFriends] Cannot spawn - integration not available"); return; } count = Mathf.Min(count, friendNames.Count); for (int i = 0; i < count; i++) { string text = friendNames[i % friendNames.Count]; if (isAlly) { sosigSpawner.SpawningSequence(text); } else { sosigSpawner.SpawningSequenceEnemy(1, text); } logger.LogInfo((object)$"[SteamFriends] Spawned sosig {i + 1}/{count} with friend name: {text}"); } } public void SpawnAllFriendsAsSosigs(bool isAlly) { if (!IsAvailable()) { logger.LogWarning((object)"[SteamFriends] Cannot spawn - integration not available"); return; } int num = 0; foreach (string friendName in friendNames) { if (isAlly) { sosigSpawner.SpawningSequence(friendName); } else { sosigSpawner.SpawningSequenceEnemy(1, friendName); } num++; } logger.LogInfo((object)string.Format("[SteamFriends] Spawned all {0} friends as {1}", num, isAlly ? "allies" : "enemies")); } private void Update() { if (isInitialized && steamAvailable && Time.time - lastRefreshTime > 300f) { logger.LogDebug((object)"[SteamFriends] Auto-refreshing friends list"); RefreshFriendsList(); } } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } friendNames?.Clear(); friendSteamIDs?.Clear(); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"[SteamFriends] Integration destroyed"); } } public string GetStatsInfo() { if (!isInitialized) { return "[SteamFriends] Not initialized"; } int num = 0; for (int i = 0; i < friendSteamIDs.Count; i++) { if (IsFriendOnline(i)) { num++; } } return "[SteamFriends] Stats:\n" + $" Total Friends: {friendNames.Count}\n" + $" Online Friends: {num}\n" + $" Last Refresh: {Time.time - lastRefreshTime:F1}s ago\n" + $" Steam Available: {steamAvailable}\n" + $" Integration Ready: {IsAvailable()}"; } public void LogAllFriends() { if (!isInitialized) { logger.LogWarning((object)"[SteamFriends] Not initialized"); return; } logger.LogInfo((object)$"[SteamFriends] Listing all {friendNames.Count} friends:"); for (int i = 0; i < friendNames.Count; i++) { string arg = (IsFriendOnline(i) ? "Online" : "Offline"); logger.LogInfo((object)$" [{i}] {friendNames[i]} - {arg}"); } } } public static class StovepipeIntegrationManager { public enum MalfunctionType { None, Stovepipe, DoubleFeed, FailureToFeed, FailureToEject, FailureToFire, HangFire, SquibLoad, SlamFire, OutOfBattery, BrokenExtractor, DirtyGun, AmmoIssue } public enum WeaponCategory { Unknown, Pistol, Rifle, Shotgun, SMG, LMG, AssaultRifle, Sniper, Revolver, Bolt, Pump } private static ManualLogSource logger; private static bool initialized = false; private static Type stovepipeType; private static object stovepipeInstance; private static MethodInfo forceMalfunctionMethod; private static MethodInfo checkCompatibilityMethod; private static MethodInfo getJamStateMethod; private static MethodInfo clearJamMethod; private static MethodInfo setJamChanceMethod; private static MethodInfo getMalfunctionTypeMethod; private static PropertyInfo malfunctionChanceProperty; private static PropertyInfo jamStateProperty; private static FieldInfo enabledField; private static ConfigFile config; private static Dictionary> chanceConfigs; private static Dictionary> featureConfigs; private static Dictionary> multiplierConfigs; private static Dictionary> intConfigs; private static readonly Dictionary jamCapabilityCache = new Dictionary(); private static readonly Dictionary lastJamTimes = new Dictionary(); private static readonly Dictionary lastMalfunctionTypes = new Dictionary(); private static readonly Dictionary jamCooldowns = new Dictionary(); private static DateTime lastCacheClear = DateTime.Now; private const string STOVEPIPE_GUID = "dll.stovepipe"; private const string STOVEPIPE_LEGACY_GUID = "stovepipe.weapon.jams"; private const string STOVEPIPE_ALPHA_GUID = "stovepipe.alpha"; private const string STOVEPIPE_BETA_GUID = "stovepipe.beta"; public static bool IsStovepipeAvailable { get; private set; } = false; public static string DetectedVersion { get; private set; } = "Unknown"; public static string DetectedApiVersion { get; private set; } = "Unknown"; public static int TotalMalfunctionAttempts { get; private set; } = 0; public static int SuccessfulMalfunctions { get; private set; } = 0; public static int CachedResults { get; private set; } = 0; public static int CooldownBlocked { get; private set; } = 0; public static int JamsCleared { get; private set; } = 0; public static Dictionary MalfunctionsByContext { get; private set; } = new Dictionary(); public static Dictionary MalfunctionsByWeaponType { get; private set; } = new Dictionary(); public static Dictionary MalfunctionsByType { get; private set; } = new Dictionary(); public static void Initialize(ManualLogSource logSource, ConfigFile configFile) { if (!initialized) { logger = logSource; config = configFile; logger.LogInfo((object)"[StovepipeIntegration] Initializing Stovepipe integration..."); InitializeConfiguration(); DetectStovepipe(); if (IsStovepipeAvailable) { CacheStovepipeMethods(); InitializeCompatibilityLayer(); logger.LogInfo((object)("[StovepipeIntegration] Successfully initialized with Stovepipe " + DetectedVersion + " (API: " + DetectedApiVersion + ")")); } else { logger.LogInfo((object)"[StovepipeIntegration] Stovepipe not detected - integration disabled"); } initialized = true; } } private static void InitializeConfiguration() { chanceConfigs = new Dictionary>(); featureConfigs = new Dictionary>(); multiplierConfigs = new Dictionary>(); intConfigs = new Dictionary>(); chanceConfigs["Normal"] = config.Bind("Stovepipe", "ChanceNormal", 0.01f, "Normal malfunction chance"); chanceConfigs["Combat"] = config.Bind("Stovepipe", "ChanceCombat", 0.03f, "Combat stress malfunction chance"); chanceConfigs["Dirty"] = config.Bind("Stovepipe", "ChanceDirty", 0.08f, "Dirty weapon malfunction chance"); chanceConfigs["Player"] = config.Bind("Stovepipe", "ChancePlayer", 0.02f, "Player weapon malfunction chance"); chanceConfigs["Enemy"] = config.Bind("Stovepipe", "ChanceEnemy", 0.04f, "Enemy weapon malfunction chance"); chanceConfigs["Ally"] = config.Bind("Stovepipe", "ChanceAlly", 0.015f, "Ally weapon malfunction chance"); chanceConfigs["Elite"] = config.Bind("Stovepipe", "ChanceElite", 0.005f, "Elite weapon malfunction chance"); chanceConfigs["Boss"] = config.Bind("Stovepipe", "ChanceBoss", 0.001f, "Boss weapon malfunction chance"); chanceConfigs["WornOut"] = config.Bind("Stovepipe", "ChanceWornOut", 0.12f, "Worn out weapon malfunction chance"); chanceConfigs["Overheated"] = config.Bind("Stovepipe", "ChanceOverheated", 0.06f, "Overheated weapon malfunction chance"); multiplierConfigs["Pistol"] = config.Bind("Stovepipe", "PistolMultiplier", 1.2f, "Pistol malfunction multiplier"); multiplierConfigs["Rifle"] = config.Bind("Stovepipe", "RifleMultiplier", 0.8f, "Rifle malfunction multiplier"); multiplierConfigs["Shotgun"] = config.Bind("Stovepipe", "ShotgunMultiplier", 0.6f, "Shotgun malfunction multiplier"); multiplierConfigs["SMG"] = config.Bind("Stovepipe", "SMGMultiplier", 1.4f, "SMG malfunction multiplier"); multiplierConfigs["LMG"] = config.Bind("Stovepipe", "LMGMultiplier", 1.1f, "LMG malfunction multiplier"); multiplierConfigs["AssaultRifle"] = config.Bind("Stovepipe", "AssaultRifleMultiplier", 0.9f, "Assault rifle malfunction multiplier"); multiplierConfigs["Sniper"] = config.Bind("Stovepipe", "SniperMultiplier", 0.7f, "Sniper rifle malfunction multiplier"); multiplierConfigs["Revolver"] = config.Bind("Stovepipe", "RevolverMultiplier", 0.3f, "Revolver malfunction multiplier"); multiplierConfigs["Bolt"] = config.Bind("Stovepipe", "BoltMultiplier", 0.2f, "Bolt action malfunction multiplier"); multiplierConfigs["Pump"] = config.Bind("Stovepipe", "PumpMultiplier", 0.4f, "Pump action malfunction multiplier"); multiplierConfigs["StovepipeChance"] = config.Bind("Stovepipe", "StovepipeChance", 1.5f, "Stovepipe jam chance multiplier"); multiplierConfigs["DoubleFeedChance"] = config.Bind("Stovepipe", "DoubleFeedChance", 1f, "Double feed chance multiplier"); multiplierConfigs["FailureToFeedChance"] = config.Bind("Stovepipe", "FailureToFeedChance", 1.2f, "Failure to feed chance multiplier"); multiplierConfigs["FailureToEjectChance"] = config.Bind("Stovepipe", "FailureToEjectChance", 1.1f, "Failure to eject chance multiplier"); multiplierConfigs["FailureToFireChance"] = config.Bind("Stovepipe", "FailureToFireChance", 0.8f, "Failure to fire chance multiplier"); multiplierConfigs["HangFireChance"] = config.Bind("Stovepipe", "HangFireChance", 0.3f, "Hang fire chance multiplier"); featureConfigs["Enabled"] = config.Bind("Stovepipe", "Enabled", true, "Enable Stovepipe integration"); featureConfigs["AutoClearJams"] = config.Bind("Stovepipe", "AutoClearJams", false, "Automatically clear jams after delay"); featureConfigs["ContextualMalfunctions"] = config.Bind("Stovepipe", "ContextualMalfunctions", true, "Use contextual malfunction logic"); featureConfigs["RealisticJamTypes"] = config.Bind("Stovepipe", "RealisticJamTypes", true, "Use realistic jam types based on weapon"); featureConfigs["EnableCooldowns"] = config.Bind("Stovepipe", "EnableCooldowns", true, "Enable jam cooldowns"); featureConfigs["EnableCaching"] = config.Bind("Stovepipe", "EnableCaching", true, "Enable jam capability caching"); featureConfigs["DirtAccumulation"] = config.Bind("Stovepipe", "DirtAccumulation", true, "Enable dirt accumulation system"); featureConfigs["HeatBuildup"] = config.Bind("Stovepipe", "HeatBuildup", true, "Enable heat buildup system"); featureConfigs["AmmoQualityAffectsJams"] = config.Bind("Stovepipe", "AmmoQualityAffectsJams", true, "Ammunition quality affects jam chance"); featureConfigs["WeaponConditionTracking"] = config.Bind("Stovepipe", "WeaponConditionTracking", true, "Track weapon condition for jam chances"); featureConfigs["PlayMalfunctionSounds"] = config.Bind("Stovepipe", "PlayMalfunctionSounds", true, "Play malfunction sound effects"); featureConfigs["ShowMalfunctionParticles"] = config.Bind("Stovepipe", "ShowMalfunctionParticles", true, "Show malfunction particle effects"); featureConfigs["EnableBatchJamming"] = config.Bind("Stovepipe", "EnableBatchJamming", true, "Enable batch jamming support"); featureConfigs["DebugMode"] = config.Bind("Stovepipe", "DebugMode", false, "Enable debug mode"); featureConfigs["VerboseLogging"] = config.Bind("Stovepipe", "VerboseLogging", false, "Enable verbose logging"); intConfigs["JamCooldownSeconds"] = config.Bind("Stovepipe", "JamCooldownSeconds", 5, "Cooldown between jams (seconds)"); intConfigs["AutoClearDelaySeconds"] = config.Bind("Stovepipe", "AutoClearDelaySeconds", 15, "Auto clear jam delay (seconds)"); intConfigs["CacheLifetimeMinutes"] = config.Bind("Stovepipe", "CacheLifetimeMinutes", 15, "Cache entry lifetime in minutes"); intConfigs["MaxCacheSize"] = config.Bind("Stovepipe", "MaxCacheSize", 500, "Maximum number of cached entries"); intConfigs["BatchSize"] = config.Bind("Stovepipe", "BatchSize", 5, "Maximum weapons to jam in a single batch"); intConfigs["MaxDirtLevel"] = config.Bind("Stovepipe", "MaxDirtLevel", 100, "Maximum dirt accumulation level"); intConfigs["MaxHeatLevel"] = config.Bind("Stovepipe", "MaxHeatLevel", 100, "Maximum heat buildup level"); } private static void DetectStovepipe() { try { Dictionary pluginInfos = Chainloader.PluginInfos; if (pluginInfos.ContainsKey("dll.stovepipe")) { IsStovepipeAvailable = true; DetectedVersion = pluginInfos["dll.stovepipe"].Metadata.Version.ToString(); logger.LogInfo((object)("[StovepipeIntegration] Stovepipe detected via BepInEx: v" + DetectedVersion)); } else if (pluginInfos.ContainsKey("stovepipe.weapon.jams")) { IsStovepipeAvailable = true; DetectedVersion = pluginInfos["stovepipe.weapon.jams"].Metadata.Version.ToString(); logger.LogInfo((object)("[StovepipeIntegration] Stovepipe detected via legacy GUID: v" + DetectedVersion)); } else if (pluginInfos.ContainsKey("stovepipe.alpha")) { IsStovepipeAvailable = true; DetectedVersion = pluginInfos["stovepipe.alpha"].Metadata.Version.ToString(); logger.LogInfo((object)("[StovepipeIntegration] Stovepipe Alpha detected: v" + DetectedVersion)); } else if (pluginInfos.ContainsKey("stovepipe.beta")) { IsStovepipeAvailable = true; DetectedVersion = pluginInfos["stovepipe.beta"].Metadata.Version.ToString(); logger.LogInfo((object)("[StovepipeIntegration] Stovepipe Beta detected: v" + DetectedVersion)); } else { DetectViaReflection(); } } catch (Exception ex) { logger.LogError((object)("[StovepipeIntegration] Error during Stovepipe detection: " + ex.Message)); IsStovepipeAvailable = false; } } private static void DetectViaReflection() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { Type[] types = assembly.GetTypes(); Type[] array2 = types; foreach (Type type in array2) { if (IsStovepipeType(type)) { stovepipeType = type; IsStovepipeAvailable = true; DetectedVersion = assembly.GetName().Version?.ToString() ?? "Unknown"; logger.LogInfo((object)("[StovepipeIntegration] Stovepipe detected via reflection: " + type.FullName)); return; } } } catch (Exception ex) { logger.LogDebug((object)("[StovepipeIntegration] Could not scan assembly " + assembly.FullName + ": " + ex.Message)); } } } private static bool IsStovepipeType(Type type) { if ((object)type == null) { return false; } string text = type.Name.ToLower(); string text2 = type.Namespace?.ToLower() ?? ""; return text.Contains("stovepipe") || text.Contains("jam") || text.Contains("malfunction") || text2.Contains("stovepipe") || text2.Contains("jamming") || (text.Contains("weapon") && (text.Contains("jam") || text.Contains("malfunction"))); } private static void CacheStovepipeMethods() { if ((object)stovepipeType == null) { return; } try { FieldInfo field = stovepipeType.GetField("Instance", BindingFlags.Static | BindingFlags.Public); if ((object)field == null) { field = stovepipeType.GetField("instance", BindingFlags.Static | BindingFlags.Public); } if ((object)field != null) { stovepipeInstance = field.GetValue(null); logger.LogDebug((object)"[StovepipeIntegration] Found Stovepipe instance"); } MethodInfo[] methods = stovepipeType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { string text = methodInfo.Name.ToLower(); if ((text.Contains("force") || text.Contains("trigger")) && (text.Contains("jam") || text.Contains("malfunction"))) { forceMalfunctionMethod = methodInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached force malfunction method: " + methodInfo.Name)); } else if (text.Contains("check") || text.Contains("compatible") || text.Contains("can")) { checkCompatibilityMethod = methodInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached compatibility method: " + methodInfo.Name)); } else if (text.Contains("clear") && (text.Contains("jam") || text.Contains("malfunction"))) { clearJamMethod = methodInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached clear jam method: " + methodInfo.Name)); } else if (text.Contains("get") && (text.Contains("jam") || text.Contains("state"))) { getJamStateMethod = methodInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached get jam state method: " + methodInfo.Name)); } else if (text.Contains("set") && text.Contains("chance")) { setJamChanceMethod = methodInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached set jam chance method: " + methodInfo.Name)); } else if (text.Contains("get") && text.Contains("type")) { getMalfunctionTypeMethod = methodInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached get malfunction type method: " + methodInfo.Name)); } } PropertyInfo[] properties = stovepipeType.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); PropertyInfo[] array2 = properties; foreach (PropertyInfo propertyInfo in array2) { string text2 = propertyInfo.Name.ToLower(); if (text2.Contains("chance") || text2.Contains("probability")) { malfunctionChanceProperty = propertyInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached chance property: " + propertyInfo.Name)); } else if (text2.Contains("jam") && text2.Contains("state")) { jamStateProperty = propertyInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached jam state property: " + propertyInfo.Name)); } } FieldInfo[] fields = stovepipeType.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); FieldInfo[] array3 = fields; foreach (FieldInfo fieldInfo in array3) { string text3 = fieldInfo.Name.ToLower(); if (text3.Contains("enabled") || text3.Contains("active")) { enabledField = fieldInfo; logger.LogDebug((object)("[StovepipeIntegration] Cached enabled field: " + fieldInfo.Name)); } } } catch (Exception ex) { logger.LogWarning((object)("[StovepipeIntegration] Error caching Stovepipe methods: " + ex.Message)); } } private static void InitializeCompatibilityLayer() { try { if ((object)getMalfunctionTypeMethod != null && (object)setJamChanceMethod != null) { DetectedApiVersion = "2.0+"; logger.LogDebug((object)"[StovepipeIntegration] Detected advanced API with malfunction types"); } else if ((object)forceMalfunctionMethod != null && (object)clearJamMethod != null) { DetectedApiVersion = "1.5+"; logger.LogDebug((object)"[StovepipeIntegration] Detected standard jamming API"); } else if ((object)forceMalfunctionMethod != null) { DetectedApiVersion = "1.0+"; logger.LogDebug((object)"[StovepipeIntegration] Detected basic jamming API"); } else { DetectedApiVersion = "Limited"; logger.LogWarning((object)"[StovepipeIntegration] Limited API detected - some features may not work"); } } catch (Exception ex) { logger.LogWarning((object)("[StovepipeIntegration] Error initializing compatibility layer: " + ex.Message)); DetectedApiVersion = "Unknown"; } } public static bool GetFeatureConfig(string key) { if (featureConfigs != null && featureConfigs.ContainsKey(key)) { return featureConfigs[key].Value; } return false; } public static bool TryJamWeapon(FVRFireArm firearm, string context = "Normal", float customChance = -1f, bool forceJam = false, MalfunctionType specificType = MalfunctionType.None) { //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) if (!IsIntegrationEnabled() || (Object)(object)firearm == (Object)null) { return false; } TotalMalfunctionAttempts++; try { string weaponKey = GetWeaponKey(firearm); if (featureConfigs["EnableCooldowns"].Value && IsOnCooldown(weaponKey) && !forceJam) { CooldownBlocked++; if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)("[StovepipeIntegration] Jam blocked by cooldown for " + weaponKey)); } return false; } if (featureConfigs["EnableCaching"].Value && jamCapabilityCache.ContainsKey(weaponKey)) { CachedResults++; if (!jamCapabilityCache[weaponKey]) { if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)("[StovepipeIntegration] Using cached incompatible result for " + weaponKey)); } return false; } } if (!CanWeaponJam(firearm) && !forceJam) { CacheJamCapability(weaponKey, canJam: false); return false; } float num = ((customChance >= 0f) ? customChance : CalculateJamChance(firearm, context)); if (!forceJam && Random.value > num) { if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)$"[StovepipeIntegration] Jam chance failed: {num:P4}"); } return false; } MalfunctionType malfunctionType = ((specificType != 0) ? specificType : DetermineMalfunctionType(firearm, context)); bool flag = PerformJamming(firearm, malfunctionType, context); if (flag) { SuccessfulMalfunctions++; UpdateMalfunctionStatistics(context, firearm, malfunctionType); if (featureConfigs["EnableCooldowns"].Value) { SetJamCooldown(weaponKey); } logger.LogInfo((object)$"[StovepipeIntegration] Successfully jammed {((Object)firearm).name} with {malfunctionType} (context: {context})"); if (featureConfigs["PlayMalfunctionSounds"].Value) { PlayMalfunctionSound(((Component)firearm).transform.position, malfunctionType); } if (featureConfigs["ShowMalfunctionParticles"].Value) { ShowMalfunctionParticles(((Component)firearm).transform.position, malfunctionType); } if (featureConfigs["AutoClearJams"].Value) { float delay = intConfigs["AutoClearDelaySeconds"].Value; StartAutoClearCoroutine(firearm, delay); } } CacheJamCapability(weaponKey, canJam: true); return flag; } catch (Exception ex) { logger.LogError((object)("[StovepipeIntegration] Error during weapon jamming: " + ex.Message)); return false; } } public static Dictionary TryJamWeaponsBatch(List firearms, string context = "Normal", float customChance = -1f, bool forceJam = false) { Dictionary dictionary = new Dictionary(); if (!IsIntegrationEnabled() || !featureConfigs["EnableBatchJamming"].Value) { foreach (FVRFireArm firearm in firearms) { dictionary[firearm] = false; } return dictionary; } int batchSize = intConfigs["BatchSize"].Value; List> list = (from x in firearms.Select((FVRFireArm x, int i) => new { Index = i, Value = x }) group x by x.Index / batchSize into x select x.Select(v => v.Value).ToList()).ToList(); foreach (List item in list) { foreach (FVRFireArm item2 in item) { dictionary[item2] = TryJamWeapon(item2, context, customChance, forceJam); } } logger.LogDebug((object)$"[StovepipeIntegration] Batch jamming completed: {dictionary.Count((KeyValuePair r) => r.Value)}/{dictionary.Count} successful"); return dictionary; } public static bool CanWeaponJam(FVRFireArm firearm) { if (!IsIntegrationEnabled() || (Object)(object)firearm == (Object)null) { return false; } try { if ((object)checkCompatibilityMethod != null) { return (bool)checkCompatibilityMethod.Invoke(stovepipeInstance, new object[1] { firearm }); } return GetWeaponCategory(firearm) switch { WeaponCategory.Revolver => false, WeaponCategory.Bolt => multiplierConfigs["BoltMultiplier"].Value > 0.1f, WeaponCategory.Pump => multiplierConfigs["PumpMultiplier"].Value > 0.1f, _ => true, }; } catch (Exception ex) { logger.LogError((object)("[StovepipeIntegration] Error checking weapon jam capability: " + ex.Message)); return false; } } public static bool IsWeaponJammed(FVRFireArm firearm) { if ((Object)(object)firearm == (Object)null) { return false; } try { if ((object)getJamStateMethod != null) { return (bool)getJamStateMethod.Invoke(stovepipeInstance, new object[1] { firearm }); } if ((object)jamStateProperty != null) { object obj = stovepipeInstance ?? firearm; return (bool)jamStateProperty.GetValue(obj, null); } return CheckWeaponJamStateFallback(firearm); } catch (Exception ex) { logger.LogDebug((object)("[StovepipeIntegration] Error checking jam status: " + ex.Message)); return false; } } public static bool ClearWeaponJam(FVRFireArm firearm) { if ((Object)(object)firearm == (Object)null) { return false; } try { if ((object)clearJamMethod != null) { clearJamMethod.Invoke(stovepipeInstance, new object[1] { firearm }); JamsCleared++; logger.LogInfo((object)("[StovepipeIntegration] Cleared jam on " + ((Object)firearm).name)); return true; } return ClearJamFallback(firearm); } catch (Exception ex) { logger.LogError((object)("[StovepipeIntegration] Error clearing jam: " + ex.Message)); return false; } } public static string GetMalfunctionStats() { float num = ((TotalMalfunctionAttempts > 0) ? ((float)SuccessfulMalfunctions / (float)TotalMalfunctionAttempts * 100f) : 0f); string text = string.Join(", ", MalfunctionsByContext.Select, string>((KeyValuePair kvp) => $"{kvp.Key}: {kvp.Value}").ToArray()); string text2 = string.Join(", ", MalfunctionsByWeaponType.Select, string>((KeyValuePair kvp) => $"{kvp.Key}: {kvp.Value}").ToArray()); string text3 = string.Join(", ", MalfunctionsByType.Select((KeyValuePair kvp) => $"{kvp.Key}: {kvp.Value}").ToArray()); return "Stovepipe Integration Stats:\n• Status: " + (IsStovepipeAvailable ? "? Active" : "? Not Available") + "\n• Version: " + DetectedVersion + " (API: " + DetectedApiVersion + ")\n" + $"• Attempts: {TotalMalfunctionAttempts}\n" + $"• Successes: {SuccessfulMalfunctions}\n" + $"• Success Rate: {num:F1}%\n" + $"• Cached Results: {CachedResults}\n" + $"• Cooldown Blocked: {CooldownBlocked}\n" + $"• Jams Cleared: {JamsCleared}\n" + $"• Cache Size: {jamCapabilityCache.Count}\n" + "• By Context: " + text + "\n• By Weapon Type: " + text2 + "\n• By Malfunction Type: " + text3; } public static void ClearCache() { jamCapabilityCache.Clear(); lastJamTimes.Clear(); lastMalfunctionTypes.Clear(); jamCooldowns.Clear(); CachedResults = 0; logger.LogDebug((object)"[StovepipeIntegration] Cache cleared"); } public static bool IsIntegrationEnabled() { return IsStovepipeAvailable && featureConfigs["Enabled"].Value; } public static string GetCompatibilityInfo() { if (!IsStovepipeAvailable) { return "Stovepipe not detected"; } List list = new List(); if ((object)forceMalfunctionMethod != null) { list.Add("Force Malfunction"); } if ((object)checkCompatibilityMethod != null) { list.Add("Compatibility Checking"); } if ((object)getJamStateMethod != null) { list.Add("Jam State Detection"); } if ((object)clearJamMethod != null) { list.Add("Jam Clearing"); } if ((object)getMalfunctionTypeMethod != null) { list.Add("Malfunction Types"); } if ((object)setJamChanceMethod != null) { list.Add("Jam Chance Control"); } return "Stovepipe Compatibility:\n• Version: " + DetectedVersion + "\n• API Version: " + DetectedApiVersion + "\n• Available Features: " + string.Join(", ", list.ToArray()) + "\n• Integration Status: " + (IsIntegrationEnabled() ? "Active" : "Disabled"); } private static float CalculateJamChance(FVRFireArm firearm, string context) { float num = 0.01f; if (chanceConfigs.ContainsKey(context)) { num = chanceConfigs[context].Value; } else { context = context.ToLower(); num = ((!context.Contains("combat") && !context.Contains("stress")) ? ((!context.Contains("dirty") && !context.Contains("fouled")) ? ((!context.Contains("worn") && !context.Contains("old")) ? ((!context.Contains("hot") && !context.Contains("overheated")) ? ((context.Contains("elite") || context.Contains("boss")) ? chanceConfigs["Elite"].Value : (context.Contains("player") ? chanceConfigs["Player"].Value : (context.Contains("enemy") ? chanceConfigs["Enemy"].Value : ((!context.Contains("ally")) ? chanceConfigs["Normal"].Value : chanceConfigs["Ally"].Value)))) : chanceConfigs["Overheated"].Value) : chanceConfigs["WornOut"].Value) : chanceConfigs["Dirty"].Value) : chanceConfigs["Combat"].Value); } float weaponCategoryMultiplier = GetWeaponCategoryMultiplier(firearm); float num2 = num * weaponCategoryMultiplier; if (featureConfigs["ContextualMalfunctions"].Value) { num2 = ApplyContextualModifiers(num2, firearm, context); } if (featureConfigs["DebugMode"].Value) { logger.LogDebug((object)$"[StovepipeIntegration] Calculated jam chance for {((Object)firearm).name} ({context}): {num2:P4} (base: {num:P4}, category: {weaponCategoryMultiplier:F2})"); } return Mathf.Clamp01(num2); } private static float GetWeaponCategoryMultiplier(FVRFireArm firearm) { return GetWeaponCategory(firearm) switch { WeaponCategory.Pistol => multiplierConfigs["Pistol"].Value, WeaponCategory.Rifle => multiplierConfigs["Rifle"].Value, WeaponCategory.Shotgun => multiplierConfigs["Shotgun"].Value, WeaponCategory.SMG => multiplierConfigs["SMG"].Value, WeaponCategory.LMG => multiplierConfigs["LMG"].Value, WeaponCategory.AssaultRifle => multiplierConfigs["AssaultRifle"].Value, WeaponCategory.Sniper => multiplierConfigs["Sniper"].Value, WeaponCategory.Revolver => multiplierConfigs["Revolver"].Value, WeaponCategory.Bolt => multiplierConfigs["Bolt"].Value, WeaponCategory.Pump => multiplierConfigs["Pump"].Value, _ => 1f, }; } private static WeaponCategory GetWeaponCategory(FVRFireArm firearm) { string text = ((Object)firearm).name.ToLower(); string text2 = ((object)firearm).GetType().Name.ToLower(); if (text.Contains("revolver") || text2.Contains("revolver")) { return WeaponCategory.Revolver; } if (text.Contains("bolt") || text2.Contains("bolt")) { return WeaponCategory.Bolt; } if (text.Contains("pump") || text2.Contains("pump")) { return WeaponCategory.Pump; } if (text.Contains("shotgun") || text2.Contains("shotgun")) { return WeaponCategory.Shotgun; } if (text.Contains("lmg") || text.Contains("machinegun") || text2.Contains("lmg")) { return WeaponCategory.LMG; } if (text.Contains("smg") || text.Contains("submachine") || text2.Contains("smg")) { return WeaponCategory.SMG; } if (text.Contains("sniper") || text.Contains("precision") || text2.Contains("sniper")) { return WeaponCategory.Sniper; } if (text.Contains("assault") || text.Contains("carbine") || text2.Contains("assault")) { return WeaponCategory.AssaultRifle; } if (text.Contains("pistol") || text.Contains("handgun") || text2.Contains("pistol")) { return WeaponCategory.Pistol; } if (text.Contains("rifle") || text2.Contains("rifle")) { return WeaponCategory.Rifle; } return WeaponCategory.Unknown; } private static MalfunctionType DetermineMalfunctionType(FVRFireArm firearm, string context) { if (!featureConfigs["RealisticJamTypes"].Value) { return MalfunctionType.Stovepipe; } WeaponCategory weaponCategory = GetWeaponCategory(firearm); context = context.ToLower(); if (context.Contains("dirty")) { return (Random.value < 0.6f) ? MalfunctionType.FailureToFeed : MalfunctionType.FailureToEject; } if (context.Contains("overheated")) { return (Random.value < 0.7f) ? MalfunctionType.FailureToEject : MalfunctionType.DoubleFeed; } return weaponCategory switch { WeaponCategory.Pistol => GetRandomMalfunctionType(new MalfunctionType[4] { MalfunctionType.Stovepipe, MalfunctionType.FailureToFeed, MalfunctionType.FailureToEject, MalfunctionType.FailureToFire }), WeaponCategory.SMG => GetRandomMalfunctionType(new MalfunctionType[4] { MalfunctionType.DoubleFeed, MalfunctionType.Stovepipe, MalfunctionType.FailureToFeed, MalfunctionType.FailureToEject }), WeaponCategory.LMG => GetRandomMalfunctionType(new MalfunctionType[4] { MalfunctionType.FailureToEject, MalfunctionType.DoubleFeed, MalfunctionType.DirtyGun, MalfunctionType.OutOfBattery }), WeaponCategory.Revolver => GetRandomMalfunctionType(new MalfunctionType[3] { MalfunctionType.FailureToFire, MalfunctionType.HangFire, MalfunctionType.AmmoIssue }), _ => GetRandomMalfunctionType(new MalfunctionType[4] { MalfunctionType.Stovepipe, MalfunctionType.FailureToFeed, MalfunctionType.FailureToEject, MalfunctionType.FailureToFire }), }; } private static MalfunctionType GetRandomMalfunctionType(MalfunctionType[] types) { return types[Random.Range(0, types.Length)]; } private static float ApplyContextualModifiers(float baseChance, FVRFireArm firearm, string context) { float num = 1f; if (featureConfigs["DirtAccumulation"].Value) { int estimatedRoundsFired = GetEstimatedRoundsFired(firearm); if (estimatedRoundsFired > 100) { num *= 1f + (float)estimatedRoundsFired / 1000f; } } if (featureConfigs["HeatBuildup"].Value) { float timeSinceLastShot = GetTimeSinceLastShot(firearm); if (timeSinceLastShot < 2f) { num *= 1.5f; } } if (featureConfigs["WeaponConditionTracking"].Value) { float weaponCondition = GetWeaponCondition(firearm); num *= 2f - weaponCondition; } return baseChance * num; } private static bool PerformJamming(FVRFireArm firearm, MalfunctionType jamType, string context) { if ((object)forceMalfunctionMethod == null) { logger.LogWarning((object)"[StovepipeIntegration] No force malfunction method available"); return false; } try { ParameterInfo[] parameters = forceMalfunctionMethod.GetParameters(); if (parameters.Length == 1) { forceMalfunctionMethod.Invoke(stovepipeInstance, new object[1] { firearm }); } else if (parameters.Length == 2) { forceMalfunctionMethod.Invoke(stovepipeInstance, new object[2] { firearm, (int)jamType }); } else if (parameters.Length == 3) { forceMalfunctionMethod.Invoke(stovepipeInstance, new object[3] { firearm, (int)jamType, context }); } else { forceMalfunctionMethod.Invoke(stovepipeInstance, new object[1] { firearm }); } string weaponKey = GetWeaponKey(firearm); lastJamTimes[weaponKey] = DateTime.Now; lastMalfunctionTypes[weaponKey] = jamType; return true; } catch (Exception ex) { logger.LogError((object)("[StovepipeIntegration] Jamming failed: " + ex.Message)); return false; } } private static void PlayMalfunctionSound(Vector3 position, MalfunctionType jamType) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) try { Type typeFromHandle = typeof(AudioManager); MethodInfo method = typeFromHandle.GetMethod("PlayStovepipeEffect", BindingFlags.Static | BindingFlags.Public); if ((object)method != null) { string malfunctionSoundName = GetMalfunctionSoundName(jamType); method.Invoke(null, new object[2] { position, malfunctionSoundName }); } else { logger.LogDebug((object)$"[StovepipeIntegration] Playing malfunction sound ({jamType}) at {position}"); } } catch (Exception ex) { logger.LogDebug((object)("[StovepipeIntegration] Could not play malfunction sound: " + ex.Message)); } } private static void ShowMalfunctionParticles(Vector3 position, MalfunctionType jamType) { //IL_0058: 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) try { Type typeFromHandle = typeof(EffectsManager); MethodInfo method = typeFromHandle.GetMethod("PlayStovepipeParticles", BindingFlags.Static | BindingFlags.Public); if ((object)method != null) { method.Invoke(null, new object[2] { position, jamType }); } else { logger.LogDebug((object)$"[StovepipeIntegration] Showing malfunction particles ({jamType}) at {position}"); } } catch (Exception ex) { logger.LogDebug((object)("[StovepipeIntegration] Could not show malfunction particles: " + ex.Message)); } } private static string GetMalfunctionSoundName(MalfunctionType jamType) { return jamType switch { MalfunctionType.Stovepipe => "stovepipe/stovepipe_jam.wav", MalfunctionType.DoubleFeed => "stovepipe/double_feed.wav", MalfunctionType.FailureToFeed => "stovepipe/failure_to_feed.wav", MalfunctionType.FailureToEject => "stovepipe/failure_to_eject.wav", MalfunctionType.FailureToFire => "stovepipe/failure_to_fire.wav", MalfunctionType.HangFire => "stovepipe/hang_fire.wav", _ => "stovepipe/generic_jam.wav", }; } private static bool IsOnCooldown(string weaponKey) { if (!jamCooldowns.ContainsKey(weaponKey)) { return false; } DateTime dateTime = jamCooldowns[weaponKey].AddSeconds(intConfigs["JamCooldownSeconds"].Value); return DateTime.Now < dateTime; } private static void SetJamCooldown(string weaponKey) { jamCooldowns[weaponKey] = DateTime.Now; } private static void StartAutoClearCoroutine(FVRFireArm firearm, float delay) { logger.LogDebug((object)$"[StovepipeIntegration] Auto-clear scheduled for {((Object)firearm).name} in {delay} seconds"); } private static void UpdateMalfunctionStatistics(string context, FVRFireArm firearm, MalfunctionType jamType) { if (!MalfunctionsByContext.ContainsKey(context)) { MalfunctionsByContext[context] = 0; } MalfunctionsByContext[context]++; string weaponTypeName = GetWeaponTypeName(firearm); if (!MalfunctionsByWeaponType.ContainsKey(weaponTypeName)) { MalfunctionsByWeaponType[weaponTypeName] = 0; } MalfunctionsByWeaponType[weaponTypeName]++; if (!MalfunctionsByType.ContainsKey(jamType)) { MalfunctionsByType[jamType] = 0; } MalfunctionsByType[jamType]++; } private static string GetWeaponTypeName(FVRFireArm firearm) { return GetWeaponCategory(firearm).ToString(); } private static bool CheckWeaponJamStateFallback(FVRFireArm firearm) { try { return false; } catch { return false; } } private static bool ClearJamFallback(FVRFireArm firearm) { try { logger.LogWarning((object)"[StovepipeIntegration] Using limited fallback jam clearing"); return false; } catch { return false; } } private static string GetWeaponKey(FVRFireArm firearm) { try { if (((FVRPhysicalObject)firearm).ObjectWrapper?.ItemID != null) { return ((FVRPhysicalObject)firearm).ObjectWrapper.ItemID; } return ((Object)((Component)firearm).gameObject).GetInstanceID().ToString(); } catch { return ((object)firearm).GetHashCode().ToString(); } } private static void CacheJamCapability(string weaponKey, bool canJam) { if (featureConfigs["EnableCaching"].Value) { jamCapabilityCache[weaponKey] = canJam; if (jamCapabilityCache.Count > intConfigs["MaxCacheSize"].Value) { CleanOldCacheEntries(forceClear: true); } if ((DateTime.Now - lastCacheClear).TotalMinutes > 5.0) { CleanOldCacheEntries(); lastCacheClear = DateTime.Now; } } } private static void CleanOldCacheEntries(bool forceClear = false) { DateTime dateTime = DateTime.Now.AddMinutes(-intConfigs["CacheLifetimeMinutes"].Value); List list = new List(); foreach (KeyValuePair lastJamTime in lastJamTimes) { if (lastJamTime.Value < dateTime || forceClear) { list.Add(lastJamTime.Key); } } if (forceClear && list.Count < jamCapabilityCache.Count / 2) { IEnumerable> source = lastJamTimes.OrderBy, DateTime>((KeyValuePair kvp) => kvp.Value).Take(jamCapabilityCache.Count / 2); list.AddRange(source.Select((KeyValuePair kvp) => kvp.Key)); } foreach (string item in list) { jamCapabilityCache.Remove(item); lastJamTimes.Remove(item); lastMalfunctionTypes.Remove(item); jamCooldowns.Remove(item); } if (list.Count > 0) { logger.LogDebug((object)$"[StovepipeIntegration] Cleaned {list.Count} cache entries"); } } private static int GetEstimatedRoundsFired(FVRFireArm firearm) { return Random.Range(0, 500); } private static float GetTimeSinceLastShot(FVRFireArm firearm) { return Random.Range(0f, 10f); } private static float GetWeaponCondition(FVRFireArm firearm) { return Random.Range(0.7f, 1f); } } public class TNHCustomizerIntegration : MonoBehaviour { public class CustomTNHCharacter { public string CharacterName { get; set; } public string DisplayName { get; set; } public string Description { get; set; } public List StartingEquipment { get; set; } public int StartingTokens { get; set; } public int StartingHealth { get; set; } public int RequiredHolds { get; set; } public List PrimaryWeaponPool { get; set; } public List SecondaryWeaponPool { get; set; } public List TertiaryWeaponPool { get; set; } public List ShieldPool { get; set; } public List ConsumablePool { get; set; } public List EnemyPool { get; set; } public float EnemyHealthMultiplier { get; set; } public float EnemySpeedMultiplier { get; set; } public bool UnlimitedAmmo { get; set; } public bool UnlimitedTokens { get; set; } public float HealthMultiplier { get; set; } public CustomTNHCharacter() { StartingEquipment = new List(); PrimaryWeaponPool = new List(); SecondaryWeaponPool = new List(); TertiaryWeaponPool = new List(); ShieldPool = new List(); ConsumablePool = new List(); EnemyPool = new List(); RequiredHolds = 5; StartingTokens = 3; StartingHealth = 1000; EnemyHealthMultiplier = 1f; EnemySpeedMultiplier = 1f; HealthMultiplier = 1f; } } private ManualLogSource logger; private H3TVRImproved plugin; private ConfigEntry enableCustomCharacters; private ConfigEntry enableCustomPools; private ConfigEntry enableProgressionMods; private ConfigEntry enableSpawnMods; private ConfigEntry customCharacterName; private ConfigEntry customStartingTokens; private ConfigEntry customMaxHealth; private ConfigEntry unlimitedAmmo; private ConfigEntry unlimitedTokens; private ConfigEntry healthMultiplier; private ConfigEntry sosigHealthMultiplier; private ConfigEntry sosigSpeedMultiplier; private ConfigEntry customHoldCount; private Dictionary customCharacters = new Dictionary(); private CustomTNHCharacter activeCharacter; public static TNHCustomizerIntegration Instance { get; private set; } public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource) { if ((Object)(object)Instance != (Object)null) { Object.Destroy((Object)(object)this); return; } Instance = this; plugin = pluginInstance; logger = logSource; InitializeConfiguration(); LoadDefaultCharacters(); LoadCustomCharacters(); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"TNH Customizer Integration initialized"); } } private void InitializeConfiguration() { H3TVRImproved h3TVRImproved = plugin; if (((h3TVRImproved != null) ? ((BaseUnityPlugin)h3TVRImproved).Config : null) == null) { return; } try { enableCustomCharacters = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "EnableCustomCharacters", true, "Enable custom TNH character creation"); enableCustomPools = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "EnableCustomPools", true, "Enable custom weapon/equipment pools"); enableProgressionMods = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "EnableProgressionMods", true, "Enable progression modifications (hold count, tokens, etc.)"); enableSpawnMods = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "EnableSpawnMods", true, "Enable spawn modifications (enemy types, health, speed)"); customCharacterName = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "ActiveCharacter", "Default", "Name of the active custom character to use"); customStartingTokens = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "StartingTokens", 3, "Starting tokens for custom characters"); customMaxHealth = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "MaxHealth", 1000, "Maximum health for custom characters"); unlimitedAmmo = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "UnlimitedAmmo", false, "Enable unlimited ammo for custom characters"); unlimitedTokens = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "UnlimitedTokens", false, "Enable unlimited tokens for custom characters"); healthMultiplier = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "HealthMultiplier", 1f, "Player health multiplier"); sosigHealthMultiplier = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "SosigHealthMultiplier", 1f, "Enemy sosig health multiplier"); sosigSpeedMultiplier = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "SosigSpeedMultiplier", 1f, "Enemy sosig speed multiplier"); customHoldCount = ((BaseUnityPlugin)plugin).Config.Bind("TNH Customizer", "RequiredHolds", 5, "Number of holds required to complete custom TNH"); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"TNH Customizer configuration initialized"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Config init failed: " + ex.Message)); } } } private void LoadDefaultCharacters() { try { CustomTNHCharacter value = new CustomTNHCharacter { CharacterName = "EasyMode", DisplayName = "Easy Mode", Description = "For beginners - More health, tokens, and easier enemies", StartingTokens = 10, StartingHealth = 2000, RequiredHolds = 3, UnlimitedAmmo = false, UnlimitedTokens = false, HealthMultiplier = 2f, EnemyHealthMultiplier = 0.5f, EnemySpeedMultiplier = 0.8f }; customCharacters["EasyMode"] = value; CustomTNHCharacter value2 = new CustomTNHCharacter { CharacterName = "HardMode", DisplayName = "Hard Mode", Description = "For veterans - Less health, tokens, tougher enemies", StartingTokens = 1, StartingHealth = 500, RequiredHolds = 7, UnlimitedAmmo = false, UnlimitedTokens = false, HealthMultiplier = 0.5f, EnemyHealthMultiplier = 2f, EnemySpeedMultiplier = 1.5f }; customCharacters["HardMode"] = value2; CustomTNHCharacter value3 = new CustomTNHCharacter { CharacterName = "InfiniteMode", DisplayName = "Infinite Resources", Description = "Unlimited ammo and tokens for sandbox play", StartingTokens = 999, StartingHealth = 1000, RequiredHolds = 5, UnlimitedAmmo = true, UnlimitedTokens = true, HealthMultiplier = 1f, EnemyHealthMultiplier = 1f, EnemySpeedMultiplier = 1f }; customCharacters["InfiniteMode"] = value3; CustomTNHCharacter value4 = new CustomTNHCharacter { CharacterName = "SpeedRun", DisplayName = "Speed Runner", Description = "Fast-paced mode - Quick holds, no encryption", StartingTokens = 5, StartingHealth = 1000, RequiredHolds = 5, UnlimitedAmmo = false, UnlimitedTokens = false, HealthMultiplier = 1f, EnemyHealthMultiplier = 0.8f, EnemySpeedMultiplier = 1.2f }; customCharacters["SpeedRun"] = value4; CustomTNHCharacter value5 = new CustomTNHCharacter { CharacterName = "RealisticMode", DisplayName = "Realistic", Description = "Realistic combat - Low health, realistic enemy behavior", StartingTokens = 2, StartingHealth = 100, RequiredHolds = 5, UnlimitedAmmo = false, UnlimitedTokens = false, HealthMultiplier = 0.1f, EnemyHealthMultiplier = 0.3f, EnemySpeedMultiplier = 1f }; customCharacters["RealisticMode"] = value5; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)$"Loaded {customCharacters.Count} default TNH characters"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to load default characters: " + ex.Message)); } } } private void LoadCustomCharacters() { try { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Custom character loading from files not yet implemented"); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to load custom characters: " + ex.Message)); } } } private void Update() { if (!enableCustomCharacters.Value || (Object)(object)GM.TNH_Manager == (Object)null) { return; } try { ApplyCharacterModifications(); } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Error applying TNH modifications: " + ex.Message)); } } } private void ApplyCharacterModifications() { if (activeCharacter == null) { return; } TNH_Manager tNH_Manager = GM.TNH_Manager; if (!((Object)(object)tNH_Manager == (Object)null)) { if (activeCharacter.UnlimitedTokens || unlimitedTokens.Value) { tNH_Manager.m_numTokens = 999; } if (activeCharacter.HealthMultiplier != 1f) { } ApplyEnemyModifications(); } } private void ApplyEnemyModifications() { if (!enableSpawnMods.Value) { return; } try { TNH_Manager tNH_Manager = GM.TNH_Manager; if ((Object)(object)tNH_Manager == (Object)null || (Object)(object)tNH_Manager.m_curHoldPoint == (Object)null) { return; } TNH_HoldPoint curHoldPoint = tNH_Manager.m_curHoldPoint; if (curHoldPoint.m_activeSosigs == null) { return; } foreach (Sosig activeSosig in curHoldPoint.m_activeSosigs) { if ((Object)(object)activeSosig == (Object)null) { continue; } float num = activeCharacter?.EnemyHealthMultiplier ?? sosigHealthMultiplier.Value; if (num != 1f) { foreach (SosigLink link in activeSosig.Links) { if ((Object)(object)link != (Object)null) { link.m_integrity *= num; } } } float num2 = activeCharacter?.EnemySpeedMultiplier ?? sosigSpeedMultiplier.Value; if (num2 != 1f) { activeSosig.Speed_Walk *= num2; activeSosig.Speed_Run *= num2; } } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)("Failed to apply enemy modifications: " + ex.Message)); } } } public List GetAvailableCharacters() { return customCharacters.Keys.ToList(); } public CustomTNHCharacter GetCharacter(string characterName) { if (customCharacters.ContainsKey(characterName)) { return customCharacters[characterName]; } return null; } public bool SetActiveCharacter(string characterName) { if (customCharacters.ContainsKey(characterName)) { activeCharacter = customCharacters[characterName]; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Activated TNH character: " + activeCharacter.DisplayName)); } return true; } ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogWarning((object)("Character not found: " + characterName)); } return false; } public bool CreateCustomCharacter(CustomTNHCharacter character) { if (string.IsNullOrEmpty(character.CharacterName)) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)"Cannot create character with empty name"); } return false; } customCharacters[character.CharacterName] = character; ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)("Created custom TNH character: " + character.DisplayName)); } return true; } public bool RemoveCustomCharacter(string characterName) { if (customCharacters.ContainsKey(characterName)) { customCharacters.Remove(characterName); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Removed custom TNH character: " + characterName)); } return true; } return false; } public CustomTNHCharacter GetActiveCharacter() { return activeCharacter; } public bool IsEnabled() { return enableCustomCharacters.Value; } } public class AudioManager : MonoBehaviour { [CompilerGenerated] private sealed class d__107 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string sourceKey; public float delay; public AudioManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__107(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; if (<>4__this.activeSources.ContainsKey(sourceKey)) { if ((Object)(object)<>4__this.activeSources[sourceKey] != (Object)null && (Object)(object)((Component)<>4__this.activeSources[sourceKey]).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)<>4__this.activeSources[sourceKey]).gameObject); } <>4__this.activeSources.Remove(sourceKey); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__78 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string filePath; public string effectKey; public AudioManager <>4__this; private string 5__1; private WWW 5__2; private AudioClip 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__78(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__1 = null; 5__2 = null; 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = "file://" + filePath; 5__2 = new WWW(5__1); <>1__state = -3; <>2__current = 5__2; <>1__state = 1; return true; case 1: <>1__state = -3; if (string.IsNullOrEmpty(5__2.error)) { 5__3 = WWWAudioExtensions.GetAudioClip(5__2, false, false, <>4__this.GetAudioType(filePath)); if ((Object)(object)5__3 != (Object)null) { ((Object)5__3).name = effectKey; <>4__this.audioClips[effectKey] = 5__3; <>4__this.logger.LogDebug((object)("[AudioManager] Loaded: " + effectKey + " from " + filePath)); } 5__3 = null; } else { <>4__this.logger.LogWarning((object)("[AudioManager] Failed to load " + Path.GetFileName(filePath) + ": " + 5__2.error)); } <>m__Finally1(); 5__2 = null; return false; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (5__2 != null) { ((IDisposable)5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__99 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string filePath; public string effectKey; public AudioManager <>4__this; private string 5__1; private WWW 5__2; private AudioClip 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__99(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__1 = null; 5__2 = null; 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = "file://" + filePath; 5__2 = new WWW(5__1); <>1__state = -3; <>2__current = 5__2; <>1__state = 1; return true; case 1: <>1__state = -3; if (string.IsNullOrEmpty(5__2.error)) { 5__3 = WWWAudioExtensions.GetAudioClip(5__2, false, false, <>4__this.GetAudioType(filePath)); if ((Object)(object)5__3 != (Object)null) { ((Object)5__3).name = effectKey; <>4__this.audioClips[effectKey] = 5__3; <>4__this.effectNameToFile[effectKey] = filePath; <>4__this.logger.LogInfo((object)("[AudioManager] Loaded custom: " + effectKey)); } 5__3 = null; } <>m__Finally1(); 5__2 = null; return false; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (5__2 != null) { ((IDisposable)5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string AUDIO_FOLDER = "H3TVR_Audio"; private const string AUDIO_PATHS_CONFIG = "H3TVR_AudioPaths.ini"; private const float DEFAULT_VOLUME = 0.7f; private const float DEFAULT_PITCH = 1f; private const float SPATIAL_BLEND_2D = 0f; private const float SPATIAL_BLEND_3D = 1f; private const int CLEANUP_FRAME_THRESHOLD = 5; private const float SYNC_LOAD_TIMEOUT = 30f; private H3TVRImproved plugin; private ManualLogSource logger; private bool isInitialized = false; private string audioFolderPath; private string audioPathsConfigFile; private Dictionary audioClips = new Dictionary(); private Dictionary activeSources = new Dictionary(); private Dictionary effectNameToFile = new Dictionary(); private List audioSearchPaths = new List(); private ConfigEntry enableAudioEffects; private ConfigEntry masterVolume; private ConfigEntry effectsVolume; private ConfigEntry weaponSoundsVolume; private ConfigEntry ambientSoundsVolume; private ConfigEntry enableSpatialAudio; private ConfigEntry enable3DAudio; private ConfigEntry maxAudioDistance; private ConfigEntry maxSimultaneousSounds; private ConfigEntry shurikenVolume; private ConfigEntry hydrationVolume; private ConfigEntry slomoVolume; private ConfigEntry dangerCloseVolume; private ConfigEntry skittySubGunVolume; private ConfigEntry destroyQuickbeltVolume; private ConfigEntry wondertoyVolume; private ConfigEntry jeditoyVolume; private ConfigEntry customAudioDirectory1; private ConfigEntry customAudioDirectory2; private ConfigEntry customAudioDirectory3; private ConfigEntry shurikenThrowPath; private ConfigEntry shurikenSpawnPath; private ConfigEntry hydrationDrinkPath; private ConfigEntry hydrationSpawnPath; private ConfigEntry slomoStartPath; private ConfigEntry slomoEndPath; private ConfigEntry slomoActivePath; private ConfigEntry dangerClosePath; private ConfigEntry explosionPath; private ConfigEntry gunSpawnPath; private ConfigEntry destroyQuickbeltPath; private ConfigEntry itemDestroyPath; private ConfigEntry wondertoySpawnPath; private ConfigEntry wondertoyActivatePath; private ConfigEntry jeditoySpawnPath; private ConfigEntry uiConfirmPath; private ConfigEntry uiErrorPath; private ConfigEntry systemReadyPath; private ConfigEntry stovepipeJamPath; private ConfigEntry stovepipeDoubleFeedPath; private ConfigEntry stovepipeFailureToFeedPath; private ConfigEntry stovepipeFailureToEjectPath; private ConfigEntry stovepipeFailureToFirePath; private ConfigEntry stovepipeHangFirePath; private ConfigEntry stovepipeClearJamPath; private ConfigEntry stovepipeCyclingPath; private ConfigEntry stovepipeGenericPath; public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (isInitialized) { return; } plugin = pluginInstance; logger = logSource; try { SetupConfiguration(); SetupAudioFolders(); LoadCustomPathsConfig(); LoadConfiguredPaths(); ScanForAudioFiles(); LoadAudioClips(); isInitialized = true; logger.LogInfo((object)$"[AudioManager] Initialized - Found {effectNameToFile.Count} audio files across {audioSearchPaths.Count} locations"); PlayEffect("system_ready", Vector3.zero, is3D: false); } catch (Exception ex) { logger.LogError((object)("[AudioManager] Init failed: " + ex.Message)); } } private void SetupConfiguration() { enableAudioEffects = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "EnableAudioEffects", true, "Enable all audio effects"); masterVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "MasterVolume", 1f, "Master volume (0.0-1.0)"); effectsVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "EffectsVolume", 0.8f, "Effects volume (0.0-1.0)"); weaponSoundsVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "WeaponSoundsVolume", 0.9f, "Weapon sounds volume (0.0-1.0)"); ambientSoundsVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "AmbientSoundsVolume", 0.6f, "Ambient sounds volume (0.0-1.0)"); enableSpatialAudio = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "EnableSpatialAudio", true, "Enable 3D positional audio"); enable3DAudio = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "Enable3DAudio", true, "Enable full 3D audio processing"); maxAudioDistance = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "MaxAudioDistance", 50f, "Max distance for 3D audio"); maxSimultaneousSounds = ((BaseUnityPlugin)plugin).Config.Bind("Audio", "MaxSimultaneousSounds", 10, "Max simultaneous sounds"); shurikenVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "ShurikenVolume", 0.8f, "Shuriken sounds volume"); hydrationVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "HydrationVolume", 0.7f, "Hydration sounds volume"); slomoVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "SlomoVolume", 0.9f, "Slomo effects volume"); dangerCloseVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "DangerCloseVolume", 1f, "Danger close volume"); skittySubGunVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "SkittySubGunVolume", 0.8f, "Weapon spawn volume"); destroyQuickbeltVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "DestroyQuickbeltVolume", 0.6f, "Destruction volume"); wondertoyVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "WondertoyVolume", 0.7f, "Wondertoy volume"); jeditoyVolume = ((BaseUnityPlugin)plugin).Config.Bind("Audio.Effects", "JeditoyVolume", 0.7f, "Jeditoy volume"); customAudioDirectory1 = ((BaseUnityPlugin)plugin).Config.Bind("Audio.CustomPaths", "CustomDirectory1", "", "Additional audio directory (can be anywhere on your computer, e.g., C:\\My Sounds\\Game Audio)"); customAudioDirectory2 = ((BaseUnityPlugin)plugin).Config.Bind("Audio.CustomPaths", "CustomDirectory2", "", "Additional audio directory (can be anywhere on your computer)"); customAudioDirectory3 = ((BaseUnityPlugin)plugin).Config.Bind("Audio.CustomPaths", "CustomDirectory3", "", "Additional audio directory (can be anywhere on your computer)"); shurikenThrowPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "ShurikenThrow", "", "Full path to shuriken throw sound (e.g., C:\\My Audio\\shuriken.wav). Leave empty for auto-detection."); shurikenSpawnPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "ShurikenSpawn", "", "Full path to shuriken spawn sound. Leave empty for auto-detection."); hydrationDrinkPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "HydrationDrink", "", "Full path to hydration drink sound. Leave empty for auto-detection."); hydrationSpawnPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "HydrationSpawn", "", "Full path to hydration spawn sound. Leave empty for auto-detection."); slomoStartPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "SlomoStart", "", "Full path to slomo start sound. Leave empty for auto-detection."); slomoEndPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "SlomoEnd", "", "Full path to slomo end sound. Leave empty for auto-detection."); slomoActivePath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "SlomoActive", "", "Full path to slomo active loop sound. Leave empty for auto-detection."); dangerClosePath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "DangerClose", "", "Full path to danger close sound. Leave empty for auto-detection."); explosionPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "Explosion", "", "Full path to explosion sound. Leave empty for auto-detection."); gunSpawnPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "GunSpawn", "", "Full path to gun spawn sound. Leave empty for auto-detection."); destroyQuickbeltPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "DestroyQuickbelt", "", "Full path to destroy quickbelt sound. Leave empty for auto-detection."); itemDestroyPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "ItemDestroy", "", "Full path to item destroy sound. Leave empty for auto-detection."); wondertoySpawnPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "WondertoySpawn", "", "Full path to wondertoy spawn sound. Leave empty for auto-detection."); wondertoyActivatePath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "WondertoyActivate", "", "Full path to wondertoy activate sound. Leave empty for auto-detection."); jeditoySpawnPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "JeditoySpawn", "", "Full path to jeditoy spawn sound. Leave empty for auto-detection."); uiConfirmPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "UIConfirm", "", "Full path to UI confirm sound. Leave empty for auto-detection."); uiErrorPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "UIError", "", "Full path to UI error sound. Leave empty for auto-detection."); systemReadyPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths", "SystemReady", "", "Full path to system ready sound. Leave empty for auto-detection."); stovepipeJamPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "WeaponJam", "", "Full path to weapon jam sound. Leave empty for auto-detection."); stovepipeDoubleFeedPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "DoubleFeed", "", "Full path to double feed sound. Leave empty for auto-detection."); stovepipeFailureToFeedPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "FailureToFeed", "", "Full path to failure to feed sound. Leave empty for auto-detection."); stovepipeFailureToEjectPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "FailureToEject", "", "Full path to failure to eject sound. Leave empty for auto-detection."); stovepipeFailureToFirePath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "FailureToFire", "", "Full path to failure to fire sound. Leave empty for auto-detection."); stovepipeHangFirePath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "HangFire", "", "Full path to hang fire sound. Leave empty for auto-detection."); stovepipeClearJamPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "ClearJam", "", "Full path to clear jam sound. Leave empty for auto-detection."); stovepipeCyclingPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "Cycling", "", "Full path to cycling sound. Leave empty for auto-detection."); stovepipeGenericPath = ((BaseUnityPlugin)plugin).Config.Bind("Audio.FilePaths.Stovepipe", "GenericMalfunction", "", "Full path to generic malfunction sound. Leave empty for auto-detection."); } private void LoadConfiguredPaths() { RegisterConfigPath("shuriken", shurikenThrowPath.Value); RegisterConfigPath("shuriken_spawn", shurikenSpawnPath.Value); RegisterConfigPath("hydration", hydrationDrinkPath.Value); RegisterConfigPath("hydration_spawn", hydrationSpawnPath.Value); RegisterConfigPath("slomo_start", slomoStartPath.Value); RegisterConfigPath("slomo_end", slomoEndPath.Value); RegisterConfigPath("slomo_active", slomoActivePath.Value); RegisterConfigPath("danger_close", dangerClosePath.Value); RegisterConfigPath("explosion", explosionPath.Value); RegisterConfigPath("gun_spawn", gunSpawnPath.Value); RegisterConfigPath("skitty_sub_gun", gunSpawnPath.Value); RegisterConfigPath("destroy_quickbelt", destroyQuickbeltPath.Value); RegisterConfigPath("item_destroy", itemDestroyPath.Value); RegisterConfigPath("wondertoy", wondertoySpawnPath.Value); RegisterConfigPath("wondertoy_activate", wondertoyActivatePath.Value); RegisterConfigPath("jeditoy", jeditoySpawnPath.Value); RegisterConfigPath("ui_confirm", uiConfirmPath.Value); RegisterConfigPath("ui_error", uiErrorPath.Value); RegisterConfigPath("system_ready", systemReadyPath.Value); RegisterConfigPath("stovepipe_jam", stovepipeJamPath.Value); RegisterConfigPath("stovepipe_malfunction", stovepipeJamPath.Value); RegisterConfigPath("stovepipe_double_feed", stovepipeDoubleFeedPath.Value); RegisterConfigPath("stovepipe_failure_to_feed", stovepipeFailureToFeedPath.Value); RegisterConfigPath("stovepipe_failure_to_eject", stovepipeFailureToEjectPath.Value); RegisterConfigPath("stovepipe_failure_to_fire", stovepipeFailureToFirePath.Value); RegisterConfigPath("stovepipe_hang_fire", stovepipeHangFirePath.Value); RegisterConfigPath("stovepipe_clear_jam", stovepipeClearJamPath.Value); RegisterConfigPath("stovepipe_cycling", stovepipeCyclingPath.Value); RegisterConfigPath("stovepipe_generic", stovepipeGenericPath.Value); } private void RegisterConfigPath(string effectKey, string filePath) { if (!string.IsNullOrEmpty(filePath)) { if (File.Exists(filePath)) { effectNameToFile[effectKey] = filePath; logger.LogInfo((object)("[AudioManager] Config path registered: " + effectKey + " -> " + filePath)); } else { logger.LogWarning((object)("[AudioManager] Config path not found for " + effectKey + ": " + filePath)); } } } private void SetupAudioFolders() { try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)plugin).Info.Location); audioFolderPath = Path.Combine(directoryName, "H3TVR_Audio"); audioPathsConfigFile = Path.Combine(directoryName, "H3TVR_AudioPaths.ini"); if (!Directory.Exists(audioFolderPath)) { Directory.CreateDirectory(audioFolderPath); CreateReadme(); } audioSearchPaths.Add(audioFolderPath); AddSubdirectoriesRecursive(audioFolderPath); AddCustomDirectories(); logger.LogInfo((object)$"[AudioManager] Scanning {audioSearchPaths.Count} directories for audio files"); } catch (Exception ex) { logger.LogError((object)("[AudioManager] Folder setup failed: " + ex.Message)); } } private void AddCustomDirectories() { AddCustomDirectory(customAudioDirectory1.Value); AddCustomDirectory(customAudioDirectory2.Value); AddCustomDirectory(customAudioDirectory3.Value); } private void AddCustomDirectory(string path) { if (string.IsNullOrEmpty(path)) { return; } try { if (Directory.Exists(path)) { if (!audioSearchPaths.Contains(path)) { audioSearchPaths.Add(path); AddSubdirectoriesRecursive(path); logger.LogInfo((object)("[AudioManager] Added custom directory: " + path)); } } else { logger.LogWarning((object)("[AudioManager] Custom directory not found: " + path)); } } catch (Exception ex) { logger.LogWarning((object)("[AudioManager] Error adding custom directory " + path + ": " + ex.Message)); } } private void AddSubdirectoriesRecursive(string directory) { try { string[] directories = Directory.GetDirectories(directory); string[] array = directories; foreach (string text in array) { if (!audioSearchPaths.Contains(text)) { audioSearchPaths.Add(text); } AddSubdirectoriesRecursive(text); } } catch (Exception ex) { logger.LogWarning((object)("[AudioManager] Could not scan subdirectory: " + ex.Message)); } } private void LoadCustomPathsConfig() { if (!File.Exists(audioPathsConfigFile)) { CreatePathsConfigTemplate(); return; } try { string[] array = File.ReadAllLines(audioPathsConfigFile); int num = 0; string[] array2 = array; foreach (string text in array2) { if (text == null || text.Trim().Length == 0 || text.TrimStart(new char[0]).StartsWith("#") || text.TrimStart(new char[0]).StartsWith(";")) { continue; } string[] array3 = text.Split(new char[1] { '=' }, 2); if (array3.Length != 2) { continue; } string text2 = array3[0].Trim(); string text3 = array3[1].Trim(); if (File.Exists(text3)) { if (!effectNameToFile.ContainsKey(text2)) { effectNameToFile[text2] = text3; num++; logger.LogDebug((object)("[AudioManager] INI path loaded: " + text2 + " -> " + text3)); } } else { logger.LogWarning((object)("[AudioManager] File not found for " + text2 + ": " + text3)); } } if (num > 0) { logger.LogInfo((object)$"[AudioManager] Loaded {num} custom audio paths from INI config"); } } catch (Exception ex) { logger.LogError((object)("[AudioManager] Error loading custom paths config: " + ex.Message)); } } private void CreatePathsConfigTemplate() { string contents = "# H3TVR Enhanced Edition - Custom Audio Paths Configuration\r\n# ============================================================\r\n# \r\n# NOTE: You can now configure audio paths directly in BepInEx config!\r\n# This INI file is still supported for backwards compatibility.\r\n# BepInEx config paths take priority over this file.\r\n#\r\n# Use this file to point to audio files ANYWHERE on your computer!\r\n# Format: effectName=C:\\Full\\Path\\To\\Your\\Audio\\File.wav\r\n#\r\n# Supported formats: .wav, .ogg, .mp3, .aif, .aiff\r\n#\r\n# EXAMPLES:\r\n# shuriken=C:\\Users\\YourName\\Music\\Sound Effects\\shuriken_throw.wav\r\n# slomo_start=D:\\Game Audio\\slomo_start.ogg\r\n# explosion=E:\\Downloads\\explosion.mp3\r\n#\r\n# Available effect names:\r\n# -----------------------\r\n# Shuriken: shuriken, shuriken_spawn\r\n# Hydration: hydration, hydration_spawn\r\n# Slomo: slomo_start, slomo_end, slomo_active\r\n# Danger Close: danger_close, explosion\r\n# Weapons: gun_spawn, skitty_sub_gun\r\n# Destruction: destroy_quickbelt, item_destroy\r\n# Wondertoy: wondertoy, wondertoy_activate\r\n# UI: ui_confirm, ui_error\r\n# System: system_ready\r\n# Stovepipe: stovepipe_jam, stovepipe_malfunction, stovepipe_double_feed,\r\n# stovepipe_failure_to_feed, stovepipe_failure_to_eject,\r\n# stovepipe_failure_to_fire, stovepipe_hang_fire,\r\n# stovepipe_clear_jam, stovepipe_cycling, stovepipe_generic\r\n#\r\n# YOUR CUSTOM PATHS (uncomment and edit):\r\n# ========================================\r\n\r\n# shuriken=C:\\Path\\To\\Your\\shuriken_throw.wav\r\n# explosion=C:\\Path\\To\\Your\\explosion.wav\r\n# slomo_start=C:\\Path\\To\\Your\\slomo_start.ogg\r\n\r\n"; try { File.WriteAllText(audioPathsConfigFile, contents); logger.LogInfo((object)("[AudioManager] Created custom paths config template: " + audioPathsConfigFile)); } catch (Exception ex) { logger.LogWarning((object)("[AudioManager] Could not create paths config template: " + ex.Message)); } } private void CreateReadme() { string contents = "H3TVR Enhanced Edition - Audio Files\r\n====================================\r\n\r\nULTIMATE FLEXIBILITY - Configure audio files DIRECTLY in BepInEx config!\r\n\r\nMETHOD 1: BepInEx Config (RECOMMENDED - easiest!)\r\n Open BepInEx\\config\\com.h3tvr.improved.cfg\r\n Find [Audio.FilePaths] section\r\n Set full paths for each effect:\r\n ShurikenThrow = C:\\My Sounds\\shuriken.wav\r\n Explosion = D:\\Downloads\\boom.mp3\r\n\r\nMETHOD 2: Use H3TVR_AudioPaths.ini to point to files anywhere\r\n\r\nMETHOD 3: Place files in this folder (auto-detected by name)\r\n\r\nMETHOD 4: Add custom directories in BepInEx config\r\n\r\nSUPPORTED FORMATS: .wav, .ogg, .mp3, .aif, .aiff\r\n\r\nEFFECT FILE NAMES (case-insensitive, auto-detected):\r\n----------------------------------------------------\r\n\r\nSHURIKEN:\r\n - shuriken_throw.*\r\n - shuriken_spawn.*\r\n\r\nHYDRATION:\r\n - hydration_drink.*\r\n - hydration_spawn.*\r\n\r\nSLOMO:\r\n - slomo_start.*\r\n - slomo_end.*\r\n - slomo_active.*\r\n\r\nDANGER CLOSE:\r\n - danger_close.*\r\n - explosion.*\r\n\r\nWEAPONS:\r\n - gun_spawn.*\r\n\r\nDESTRUCTION:\r\n - destroy_quickbelt.*\r\n - item_destroy.*\r\n\r\nWONDERTOY:\r\n - wondertoy_spawn.*\r\n - wondertoy_activate.*\r\n - jeditoy_spawn.*\r\n\r\nUI SOUNDS:\r\n - ui_confirm.*\r\n - ui_error.*\r\n\r\nSYSTEM:\r\n - system_ready.*\r\n\r\nSTOVEPIPE (weapon malfunctions):\r\n - weapon_jam.*\r\n - double_feed.*\r\n - failure_to_feed.*\r\n - failure_to_eject.*\r\n - failure_to_fire.*\r\n - hang_fire.*\r\n - clear_jam.*\r\n - cycling.*\r\n - generic_malfunction.*\r\n\r\nPRIORITY ORDER:\r\n--------------\r\n1. BepInEx config paths (highest priority)\r\n2. H3TVR_AudioPaths.ini\r\n3. Auto-detected files in folders\r\n"; try { File.WriteAllText(Path.Combine(audioFolderPath, "README.txt"), contents); } catch { } } private void ScanForAudioFiles() { Dictionary dictionary = new Dictionary { { "shuriken", "shuriken_throw" }, { "shuriken_spawn", "shuriken_spawn" }, { "hydration", "hydration_drink" }, { "hydration_spawn", "hydration_spawn" }, { "slomo_start", "slomo_start" }, { "slomo_end", "slomo_end" }, { "slomo_active", "slomo_active" }, { "danger_close", "danger_close" }, { "explosion", "explosion" }, { "skitty_sub_gun", "gun_spawn" }, { "gun_spawn", "gun_spawn" }, { "destroy_quickbelt", "destroy_quickbelt" }, { "item_destroy", "item_destroy" }, { "wondertoy", "wondertoy_spawn" }, { "wondertoy_activate", "wondertoy_activate" }, { "jeditoy", "jeditoy_spawn" }, { "ui_confirm", "ui_confirm" }, { "ui_error", "ui_error" }, { "system_ready", "system_ready" }, { "stovepipe_jam", "weapon_jam" }, { "stovepipe_malfunction", "weapon_jam" }, { "stovepipe_double_feed", "double_feed" }, { "stovepipe_failure_to_feed", "failure_to_feed" }, { "stovepipe_failure_to_eject", "failure_to_eject" }, { "stovepipe_failure_to_fire", "failure_to_fire" }, { "stovepipe_hang_fire", "hang_fire" }, { "stovepipe_clear_jam", "clear_jam" }, { "stovepipe_cycling", "cycling" }, { "stovepipe_generic", "generic_malfunction" } }; string[] array = new string[5] { ".wav", ".ogg", ".mp3", ".aif", ".aiff" }; foreach (string audioSearchPath in audioSearchPaths) { if (!Directory.Exists(audioSearchPath)) { continue; } try { string[] files = Directory.GetFiles(audioSearchPath); string[] array2 = files; foreach (string text in array2) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); string value = Path.GetExtension(text).ToLower(); if (Array.IndexOf(array, value) == -1) { continue; } foreach (KeyValuePair item in dictionary) { if (fileNameWithoutExtension.Equals(item.Value, StringComparison.OrdinalIgnoreCase)) { if (!effectNameToFile.ContainsKey(item.Key)) { effectNameToFile[item.Key] = text; logger.LogDebug((object)("[AudioManager] Auto-detected: " + item.Key + " -> " + Path.GetFileName(text))); } break; } } } } catch (Exception ex) { logger.LogWarning((object)("[AudioManager] Error scanning " + audioSearchPath + ": " + ex.Message)); } } logger.LogInfo((object)$"[AudioManager] Discovered {effectNameToFile.Count} audio files"); } private void LoadAudioClips() { foreach (KeyValuePair item in effectNameToFile) { LoadAudioClip(item.Value, item.Key); } } private void LoadAudioClip(string filePath, string effectKey) { if (File.Exists(filePath)) { ((MonoBehaviour)this).StartCoroutine(LoadAudioClipCoroutine(filePath, effectKey)); } } private IEnumerator LoadAudioClipCoroutine(string filePath, string effectKey) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__78(0) { <>4__this = this, filePath = filePath, effectKey = effectKey }; } private AudioType GetAudioType(string filePath) { //IL_0056: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_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) switch (Path.GetExtension(filePath).ToLower()) { case ".wav": return (AudioType)20; case ".ogg": return (AudioType)14; case ".mp3": return (AudioType)13; case ".aif": case ".aiff": return (AudioType)2; default: return (AudioType)20; } } public void PlayShurikenSound(string action = "throw", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { string effectKey = ((action == "throw") ? "shuriken" : ("shuriken_" + action)); float volume = ((customVolume >= 0f) ? customVolume : (shurikenVolume.Value * effectsVolume.Value * masterVolume.Value)); PlayEffect(effectKey, position, is3D, volume, 1f, customFilePath); } } public void PlayHydrationSound(string action = "drink", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { string effectKey = ((action == "drink") ? "hydration" : ("hydration_" + action)); float volume = ((customVolume >= 0f) ? customVolume : (hydrationVolume.Value * effectsVolume.Value * masterVolume.Value)); PlayEffect(effectKey, position, is3D, volume, 1f, customFilePath); } } public void PlaySlomoSound(string phase = "start", Vector3 position = default(Vector3), bool is3D = false, string customFilePath = null, float customVolume = -1f) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { string effectKey = "slomo_" + phase; float volume = ((customVolume >= 0f) ? customVolume : (slomoVolume.Value * ambientSoundsVolume.Value * masterVolume.Value)); float pitch = ((phase == "active") ? Time.timeScale : 1f); PlayEffect(effectKey, position, is3D, volume, pitch, customFilePath); } } public void PlayDangerCloseSound(string type = "danger_close", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { float volume = ((customVolume >= 0f) ? customVolume : (dangerCloseVolume.Value * effectsVolume.Value * masterVolume.Value)); PlayEffect(type, position, is3D, volume, 1f, customFilePath); } } public void PlayWeaponSpawnSound(string type = "skitty_sub_gun", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { float volume = ((customVolume >= 0f) ? customVolume : (skittySubGunVolume.Value * weaponSoundsVolume.Value * masterVolume.Value)); PlayEffect(type, position, is3D, volume, 1f, customFilePath); } } public void PlayDestructionSound(string type = "destroy_quickbelt", Vector3 position = default(Vector3), bool is3D = false, string customFilePath = null, float customVolume = -1f) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { float volume = ((customVolume >= 0f) ? customVolume : (destroyQuickbeltVolume.Value * effectsVolume.Value * masterVolume.Value)); PlayEffect(type, position, is3D, volume, 1f, customFilePath); } } public void PlayWondertoySound(string action = "spawn", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { string effectKey = ((action == "spawn") ? "wondertoy" : ("wondertoy_" + action)); float volume = ((customVolume >= 0f) ? customVolume : (wondertoyVolume.Value * effectsVolume.Value * masterVolume.Value)); PlayEffect(effectKey, position, is3D, volume, 1f, customFilePath); } } public void PlayJeditoySound(string action = "spawn", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { string effectKey = ((action == "spawn") ? "jeditoy" : ("jeditoy_" + action)); float volume = ((customVolume >= 0f) ? customVolume : (jeditoyVolume.Value * effectsVolume.Value * masterVolume.Value)); PlayEffect(effectKey, position, is3D, volume, 1f, customFilePath); } } public void PlayUISound(string type = "confirm", Vector3 position = default(Vector3), string customFilePath = null, float customVolume = -1f) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (enableAudioEffects.Value) { string effectKey = "ui_" + type; float volume = ((customVolume >= 0f) ? customVolume : (effectsVolume.Value * masterVolume.Value * 0.5f)); PlayEffect(effectKey, position, is3D: false, volume, 1f, customFilePath); } } public void PlayStovepipeSound(string action, Vector3 position, bool is3D = true, string customSound = null, float volume = 1f) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (isInitialized && enableAudioEffects.Value) { string stovepipeSoundKey = GetStovepipeSoundKey(action); PlayEffect(stovepipeSoundKey, position, is3D, volume, 1f, customSound); } } public void PlayStovepipeEffect(Vector3 position, string effectType) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) PlayStovepipeSound(effectType, position); } public void RescanAudioFiles() { logger.LogInfo((object)"[AudioManager] Rescanning for audio files..."); LoadConfiguredPaths(); LoadCustomPathsConfig(); ScanForAudioFiles(); LoadAudioClips(); } public bool RegisterCustomAudioFile(string effectKey, string absoluteFilePath) { if (string.IsNullOrEmpty(effectKey) || string.IsNullOrEmpty(absoluteFilePath)) { logger.LogWarning((object)"[AudioManager] Cannot register: empty key or path"); return false; } if (!File.Exists(absoluteFilePath)) { logger.LogWarning((object)("[AudioManager] File not found: " + absoluteFilePath)); return false; } effectNameToFile[effectKey] = absoluteFilePath; LoadAudioClip(absoluteFilePath, effectKey); logger.LogInfo((object)("[AudioManager] Registered custom audio: " + effectKey + " -> " + absoluteFilePath)); return true; } private void PlayEffect(string effectKey, Vector3 position, bool is3D, float volume = 0.7f, float pitch = 1f, string customFilePath = null) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (!enableAudioEffects.Value || !isInitialized || string.IsNullOrEmpty(effectKey)) { return; } volume = Mathf.Clamp(volume, 0f, 2f); pitch = Mathf.Clamp(pitch, 0.1f, 10f); if (activeSources.Count >= maxSimultaneousSounds.Value) { CleanupFinishedSources(); if (activeSources.Count >= maxSimultaneousSounds.Value) { return; } } AudioClip audioClip = GetAudioClip(effectKey, customFilePath); if (!((Object)(object)audioClip == (Object)null)) { CreateAndPlayAudioSource(effectKey, audioClip, position, is3D, volume, pitch); } } private AudioClip GetAudioClip(string effectKey, string customFilePath) { if (!string.IsNullOrEmpty(customFilePath)) { AudioClip val = LoadCustomAudioFileSync(customFilePath); if ((Object)(object)val != (Object)null) { return val; } } if (audioClips.ContainsKey(effectKey)) { return audioClips[effectKey]; } return null; } private void CreateAndPlayAudioSource(string effectKey, AudioClip clip, Vector3 position, bool is3D, float volume, float pitch) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("H3TVR_Audio_" + effectKey); AudioSource val2 = val.AddComponent(); val2.clip = clip; val2.volume = Mathf.Clamp01(volume); val2.pitch = Mathf.Clamp(pitch, 0.1f, 3f); val2.playOnAwake = false; val2.loop = false; if (is3D && enableSpatialAudio.Value) { val2.spatialBlend = (enable3DAudio.Value ? 1f : 0.5f); val2.maxDistance = maxAudioDistance.Value; val2.rolloffMode = (AudioRolloffMode)0; val2.dopplerLevel = 0.1f; ((Component)val2).transform.position = position; } else { val2.spatialBlend = 0f; } string text = $"{effectKey}_{Time.time}_{Random.Range(1000, 9999)}"; activeSources[text] = val2; val2.Play(); ((MonoBehaviour)this).StartCoroutine(CleanupAudioSource(text, clip.length + 0.1f)); } public void StopEffectSounds(string effectKey) { if (string.IsNullOrEmpty(effectKey)) { return; } List list = new List(); foreach (KeyValuePair activeSource in activeSources) { if (!activeSource.Key.StartsWith(effectKey + "_")) { continue; } if ((Object)(object)activeSource.Value != (Object)null) { activeSource.Value.Stop(); if ((Object)(object)((Component)activeSource.Value).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)activeSource.Value).gameObject); } } list.Add(activeSource.Key); } foreach (string item in list) { activeSources.Remove(item); } } public void StopAllAudio() { foreach (KeyValuePair activeSource in activeSources) { if ((Object)(object)activeSource.Value != (Object)null) { activeSource.Value.Stop(); if ((Object)(object)((Component)activeSource.Value).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)activeSource.Value).gameObject); } } } activeSources.Clear(); } public bool LoadCustomAudioFile(string filePath, string effectKey, bool replaceExisting = true) { if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(effectKey)) { return false; } if (!File.Exists(filePath)) { return false; } if (effectNameToFile.ContainsKey(effectKey) && !replaceExisting) { return false; } ((MonoBehaviour)this).StartCoroutine(LoadCustomAudioFileCoroutine(filePath, effectKey)); return true; } private IEnumerator LoadCustomAudioFileCoroutine(string filePath, string effectKey) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__99(0) { <>4__this = this, filePath = filePath, effectKey = effectKey }; } private AudioClip LoadCustomAudioFileSync(string filePath) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) try { string text = filePath; if (!Path.IsPathRooted(filePath)) { text = null; foreach (string audioSearchPath in audioSearchPaths) { string text2 = Path.Combine(audioSearchPath, filePath); if (File.Exists(text2)) { text = text2; break; } } if (text == null) { return null; } } if (!File.Exists(text)) { return null; } string text3 = $"temp_{Path.GetFileName(text)}_{text.GetHashCode()}"; if (audioClips.ContainsKey(text3)) { return audioClips[text3]; } string text4 = "file://" + text; WWW val = new WWW(text4); try { float num = Time.realtimeSinceStartup + 30f; while (!val.isDone && string.IsNullOrEmpty(val.error)) { if (Time.realtimeSinceStartup > num) { return null; } Thread.Sleep(10); } if (string.IsNullOrEmpty(val.error)) { AudioClip audioClip = WWWAudioExtensions.GetAudioClip(val, false, false, GetAudioType(text)); if ((Object)(object)audioClip != (Object)null) { ((Object)audioClip).name = text3; audioClips[text3] = audioClip; return audioClip; } } } finally { ((IDisposable)val)?.Dispose(); } } catch { } return null; } public bool PlayLoadedEffect(string effectName, Vector3 position = default(Vector3), bool is3D = true, float volume = 0.8f, float pitch = 1f) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!enableAudioEffects.Value || !isInitialized) { return false; } if (!HasEffect(effectName)) { return false; } float volume2 = volume * effectsVolume.Value * masterVolume.Value; PlayEffect(effectName, position, is3D, volume2, pitch); return true; } public bool HasEffect(string effectName) { return !string.IsNullOrEmpty(effectName) && audioClips.ContainsKey(effectName); } public bool IsInitialized() { return isInitialized; } public void LogConfiguration() { logger.LogInfo((object)"[AudioManager] Configuration:"); logger.LogInfo((object)$" Enabled: {enableAudioEffects.Value}"); logger.LogInfo((object)$" Master Volume: {masterVolume.Value}"); logger.LogInfo((object)$" Loaded Clips: {audioClips.Count}"); logger.LogInfo((object)$" Active Sources: {activeSources.Count}"); logger.LogInfo((object)$" Search Paths: {audioSearchPaths.Count}"); logger.LogInfo((object)" Loaded Effects:"); foreach (KeyValuePair item in effectNameToFile) { logger.LogInfo((object)(" " + item.Key + " -> " + item.Value)); } } private string GetStovepipeSoundKey(string action) { string text = action.ToLower().Replace(" ", "_"); if (text == "jam" || text == "malfunction") { return "stovepipe_jam"; } return "stovepipe_" + text; } private void CleanupFinishedSources() { List list = new List(); foreach (KeyValuePair activeSource in activeSources) { if (!((Object)(object)activeSource.Value == (Object)null) && activeSource.Value.isPlaying) { continue; } list.Add(activeSource.Key); if ((Object)(object)activeSource.Value != (Object)null && (Object)(object)((Component)activeSource.Value).gameObject != (Object)null) { try { Object.Destroy((Object)(object)((Component)activeSource.Value).gameObject); } catch { } } } foreach (string item in list) { activeSources.Remove(item); } } private IEnumerator CleanupAudioSource(string sourceKey, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__107(0) { <>4__this = this, sourceKey = sourceKey, delay = delay }; } private void OnDestroy() { StopAllAudio(); foreach (AudioClip value in audioClips.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } audioClips.Clear(); effectNameToFile.Clear(); audioSearchPaths.Clear(); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"[AudioManager] Destroyed and cleaned up"); } } } public class EffectsManager : MonoBehaviour { [CompilerGenerated] private sealed class d__14 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float duration; public EffectsManager <>4__this; private float 5__1; private float 5__2; private float 5__3; private float 5__4; private float 5__5; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__14(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this.plugin.GetSlomoConfig(out 5__1, out 5__2, out 5__3, out 5__4); 5__5 = Time.timeScale; Time.timeScale = 5__1; Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency; <>4__this.slomoController?.UpdateMovementScale(Time.timeScale); <>4__this.logger.LogInfo((object)$"Pillow slow motion activated for {duration} seconds (scale: {5__1})"); <>2__current = (object)new WaitForSecondsRealtime(duration); <>1__state = 1; return true; case 1: <>1__state = -1; Time.timeScale = 5__5; Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency; <>4__this.slomoController?.UpdateMovementScale(Time.timeScale); <>4__this.logger.LogInfo((object)"Pillow slow motion effect ended"); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__21 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float duration; public EffectsManager <>4__this; private GravityMode 5__1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__21(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0087: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = GM.Options.SimulationOptions.ObjectGravityMode; GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)3; GM.CurrentSceneSettings.RefreshGravity(); <>4__this.logger.LogInfo((object)$"Pillow zero gravity activated for {duration} seconds"); <>2__current = (object)new WaitForSecondsRealtime(duration); <>1__state = 1; return true; case 1: <>1__state = -1; GM.Options.SimulationOptions.ObjectGravityMode = 5__1; GM.CurrentSceneSettings.RefreshGravity(); <>4__this.logger.LogInfo((object)"Pillow zero gravity effect ended"); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__20 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Action onComplete; public EffectsManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSecondsRealtime(1f); <>1__state = 1; return true; case 1: <>1__state = -1; onComplete?.Invoke(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__13 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Action onComplete; public EffectsManager <>4__this; private float 5__1; private float 5__2; private float 5__3; private float 5__4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this.plugin.GetSlomoConfig(out 5__1, out 5__2, out 5__3, out 5__4); <>2__current = (object)new WaitForSecondsRealtime(5__2); <>1__state = 1; return true; case 1: <>1__state = -1; onComplete?.Invoke(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__19 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Action onComplete; public EffectsManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__19(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(6f); <>1__state = 1; return true; case 1: <>1__state = -1; onComplete?.Invoke(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private H3TVRImproved plugin; private SlomoMovementController slomoController; private ManualLogSource logger; private static EffectsManager instance; private float rampStartTime; private float rampStartValue; private float rampTargetValue; private bool isRampingDown; private bool isRampingUp; public void Initialize(H3TVRImproved pluginInstance, SlomoMovementController controller, ManualLogSource logSource) { plugin = pluginInstance; slomoController = controller; logger = logSource; instance = this; rampStartTime = 0f; rampStartValue = 1f; rampTargetValue = 1f; isRampingDown = false; isRampingUp = false; } public static bool IsInitialized() { return (Object)(object)instance != (Object)null; } public void SlomoScaleDown() { plugin.GetSlomoConfig(out var maxSlomoValue, out var _, out var scaleSpeed, out var _); plugin.GetSlomoRampConfig(out bool useRamp, out string curve, out float rampDuration, out float _); if (useRamp) { if (!isRampingDown) { rampStartTime = Time.unscaledTime; rampStartValue = Time.timeScale; rampTargetValue = maxSlomoValue; isRampingDown = true; isRampingUp = false; } float num = Time.unscaledTime - rampStartTime; float num2 = Mathf.Clamp01(num / rampDuration); float num3 = ApplyEasingCurve(num2, curve); Time.timeScale = Mathf.Lerp(rampStartValue, rampTargetValue, num3); Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency; Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f); slomoController?.UpdateMovementScale(Time.timeScale); if (num2 >= 1f) { isRampingDown = false; plugin.SetSlomoStatus("Wait"); } } else { if (Time.timeScale > maxSlomoValue) { Time.timeScale -= scaleSpeed * Time.unscaledDeltaTime; Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency; Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f); slomoController?.UpdateMovementScale(Time.timeScale); } if (Time.timeScale <= maxSlomoValue) { plugin.SetSlomoStatus("Wait"); } } } public void SlomoReturn() { plugin.GetSlomoConfig(out var _, out var _, out var _, out var returnSpeed); plugin.GetSlomoRampConfig(out bool useRamp, out string curve, out float _, out float returnDuration); if (useRamp) { if (!isRampingUp) { rampStartTime = Time.unscaledTime; rampStartValue = Time.timeScale; rampTargetValue = 1f; isRampingUp = true; isRampingDown = false; } float num = Time.unscaledTime - rampStartTime; float num2 = Mathf.Clamp01(num / returnDuration); float num3 = ApplyEasingCurve(num2, curve); Time.timeScale = Mathf.Lerp(rampStartValue, rampTargetValue, num3); Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency; Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f); slomoController?.UpdateMovementScale(Time.timeScale); if (num2 >= 1f) { isRampingUp = false; } } else if (Time.timeScale != 1f) { Time.timeScale += returnSpeed * Time.unscaledDeltaTime; Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency; Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f); slomoController?.UpdateMovementScale(Time.timeScale); } } public IEnumerator SlomoWait(Action onComplete) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__13(0) { <>4__this = this, onComplete = onComplete }; } public IEnumerator ActivatePillowSlomo(float duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__14(0) { <>4__this = this, duration = duration }; } private float ApplyEasingCurve(float t, string curveType) { switch (curveType.ToLower()) { case "linear": return t; case "easein": return t * t; case "easeout": return t * (2f - t); case "easeinout": return (t < 0.5f) ? (2f * t * t) : (-1f + (4f - 2f * t) * t); case "smooth": return t * t * (3f - 2f * t); case "cinematic": return t * t * t * (t * (t * 6f - 15f) + 10f); default: logger.LogWarning((object)("Unknown easing curve: " + curveType + ". Using EaseInOut.")); return (t < 0.5f) ? (2f * t * t) : (-1f + (4f - 2f * t) * t); } } public void ZeroGravityBumpDown() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)3; GM.CurrentSceneSettings.RefreshGravity(); } catch (Exception ex) { logger.LogError((object)("ZeroGravityBumpDown failed: " + ex.Message)); } } public void ZeroGravityBumpUp() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)1; GM.CurrentSceneSettings.RefreshGravity(); } catch (Exception ex) { logger.LogError((object)("ZeroGravityBumpUp failed: " + ex.Message)); } } public void RealisticFall() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)0; GM.CurrentSceneSettings.RefreshGravity(); } catch (Exception ex) { logger.LogError((object)("RealisticFall failed: " + ex.Message)); } } public IEnumerator ZeroGWait(Action onComplete) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__19(0) { <>4__this = this, onComplete = onComplete }; } public IEnumerator RealisticFallWait(Action onComplete) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__20(0) { <>4__this = this, onComplete = onComplete }; } public IEnumerator ActivatePillowZeroGravity(float duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__21(0) { <>4__this = this, duration = duration }; } public bool CheckVRButtonPress(string buttonName) { try { FVRViveHand[] array = GM.CurrentMovementManager?.Hands; if (array == null || array.Length == 0) { return false; } switch (buttonName.ToLower()) { case "leftx": return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.AXButtonDown; case "rightx": return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.AXButtonDown; case "lefty": return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.BYButtonDown; case "righty": return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.BYButtonDown; case "leftgrip": return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.GripDown; case "rightgrip": return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.GripDown; case "lefttrigger": return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.TriggerDown; case "righttrigger": return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.TriggerDown; case "lefttouchpad": return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.TouchpadDown; case "righttouchpad": return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.TouchpadDown; default: logger.LogWarning((object)("Unknown VR button configuration: " + buttonName + ". Using default LeftX.")); return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.AXButtonDown; } } catch (Exception ex) { logger.LogError((object)("CheckVRButtonPress failed for button " + buttonName + ": " + ex.Message)); return false; } } public void EnableMeatHands() { try { FVRViveHand[] array = GM.CurrentMovementManager?.Hands; if (array == null || array.Length < 2) { logger.LogWarning((object)"Cannot enable meat hands: Hand references not available"); return; } array[0].SpawnSausageFingers(); array[1].SpawnSausageFingers(); logger.LogInfo((object)"Meat hands enabled"); } catch (Exception ex) { logger.LogError((object)("EnableMeatHands failed: " + ex.Message)); } } public static void PlayStovepipeParticles(Vector3 position, StovepipeIntegrationManager.MalfunctionType malfunctionType) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)instance == (Object)null) { EffectsManager effectsManager = instance; if (effectsManager != null) { ManualLogSource obj = effectsManager.logger; if (obj != null) { obj.LogWarning((object)"EffectsManager not initialized for Stovepipe particles"); } } return; } GameObject val = CreateStovepipeParticleEffect(position, malfunctionType); if ((Object)(object)val != (Object)null) { ManualLogSource obj2 = instance.logger; if (obj2 != null) { obj2.LogDebug((object)$"Playing Stovepipe particle effect for {malfunctionType} at {position}"); } Object.Destroy((Object)(object)val, 3f); } } catch (Exception ex) { EffectsManager effectsManager2 = instance; if (effectsManager2 != null) { ManualLogSource obj3 = effectsManager2.logger; if (obj3 != null) { obj3.LogError((object)("PlayStovepipeParticles failed: " + ex.Message)); } } } } private static GameObject CreateStovepipeParticleEffect(Vector3 position, StovepipeIntegrationManager.MalfunctionType malfunctionType) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_0214: 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_022b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject($"StovepipeEffect_{malfunctionType}"); val.transform.position = position; ParticleSystem val2 = val.AddComponent(); MainModule main = val2.main; EmissionModule emission = val2.emission; ShapeModule shape = val2.shape; VelocityOverLifetimeModule velocityOverLifetime = val2.velocityOverLifetime; switch (malfunctionType) { case StovepipeIntegrationManager.MalfunctionType.Stovepipe: ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.8f, 0.6f, 0.2f, 0.8f)); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.02f); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(2f); ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(20f); break; case StovepipeIntegrationManager.MalfunctionType.DoubleFeed: ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.7f, 0.7f, 0.2f, 0.9f)); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.015f); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1.5f); ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(30f); break; case StovepipeIntegrationManager.MalfunctionType.FailureToEject: ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.6f, 0.4f, 0.2f, 0.7f)); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.018f); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(2.5f); ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(15f); break; case StovepipeIntegrationManager.MalfunctionType.FailureToFeed: ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.8f, 0.8f, 0.3f, 0.6f)); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.012f); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1f); ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(25f); break; case StovepipeIntegrationManager.MalfunctionType.DirtyGun: ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.3f, 0.3f, 0.3f, 0.8f)); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.008f); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(3f); ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(40f); break; default: ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.5f, 0.5f, 0.5f, 0.6f)); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.01f); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1.5f); ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(20f); break; } ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.5f); ((MainModule)(ref main)).maxParticles = 50; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).angle = 15f; ((ShapeModule)(ref shape)).radius = 0.05f; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)0; return val; } catch (Exception ex) { EffectsManager effectsManager = instance; if (effectsManager != null) { ManualLogSource obj = effectsManager.logger; if (obj != null) { obj.LogError((object)("CreateStovepipeParticleEffect failed: " + ex.Message)); } } return null; } } public static void CreateMalfunctionSmokeEffect(Vector3 position, float intensity = 1f) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0029: 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_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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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) try { if (!((Object)(object)instance == (Object)null)) { GameObject val = new GameObject("MalfunctionSmoke"); val.transform.position = position; ParticleSystem val2 = val.AddComponent(); MainModule main = val2.main; EmissionModule emission = val2.emission; ShapeModule shape = val2.shape; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.2f, 0.2f, 0.2f, 0.6f)); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.1f * intensity); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(5f); ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.2f); ((MainModule)(ref main)).maxParticles = (int)(30f * intensity); ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(10f * intensity); ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)10; ((ShapeModule)(ref shape)).radius = 0.03f; Object.Destroy((Object)(object)val, 6f); ManualLogSource obj = instance.logger; if (obj != null) { obj.LogDebug((object)$"Created malfunction smoke effect at {position} with intensity {intensity}"); } } } catch (Exception ex) { EffectsManager effectsManager = instance; if (effectsManager != null) { ManualLogSource obj2 = effectsManager.logger; if (obj2 != null) { obj2.LogError((object)("CreateMalfunctionSmokeEffect failed: " + ex.Message)); } } } } } public class ChatSosigStats { public int activeSosigCount { get; set; } public int friendlyCount { get; set; } public int enemyCount { get; set; } public int queuedSpawns { get; set; } public int totalSpawned { get; set; } } public class SpawnManager : MonoBehaviour { [CompilerGenerated] private sealed class d__7 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public GameObject tippyToy; public SpawnManager <>4__this; private Rigidbody 5__1; private bool 5__2; private Quaternion 5__3; private float 5__4; private float 5__5; private Quaternion 5__6; private float 5__7; private float 5__8; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_0126: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0213: 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_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)tippyToy == (Object)null) { return false; } <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; 5__1 = tippyToy.GetComponent(); 5__2 = false; if ((Object)(object)5__1 != (Object)null) { 5__2 = 5__1.isKinematic; 5__1.isKinematic = true; } 5__3 = tippyToy.transform.rotation; 5__4 = 0.15f; 5__5 = 0f; goto IL_0173; case 2: <>1__state = -1; goto IL_0173; case 3: <>1__state = -1; 5__6 = tippyToy.transform.rotation; 5__5 = 0f; break; case 4: { <>1__state = -1; break; } IL_0173: if (5__5 < 5__4) { if ((Object)(object)tippyToy == (Object)null) { return false; } 5__5 += Time.deltaTime; 5__7 = 5__5 / 5__4; tippyToy.transform.rotation = Quaternion.Slerp(5__3, 5__3 * Quaternion.Euler(180f, 0f, 0f), 5__7); <>2__current = null; <>1__state = 2; return true; } <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 3; return true; } if (5__5 < 5__4) { if ((Object)(object)tippyToy == (Object)null) { return false; } 5__5 += Time.deltaTime; 5__8 = 5__5 / 5__4; tippyToy.transform.rotation = Quaternion.Slerp(5__6, 5__3, 5__8); <>2__current = null; <>1__state = 4; return true; } if ((Object)(object)5__1 != (Object)null) { 5__1.isKinematic = 5__2; 5__1.AddTorque(new Vector3(0.25f, 0.25f, 0.25f)); 5__1.AddForce(GM.CurrentPlayerBody.Head.forward * 25f); } <>4__this.logger.LogInfo((object)"Tippy Toy flip animation complete - should be activated!"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__16 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Vector3 targetPosition; public SpawnManager <>4__this; private string 5__1; private FVRObject 5__2; private int 5__3; private float 5__4; private int 5__5; private float 5__6; private int 5__7; private float 5__8; private Vector3 5__9; private int 5__10; private float 5__11; private Vector3 5__12; private int 5__13; private Vector3 5__14; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__16(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: 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_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Expected O, but got Unknown //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_03de: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1.5f); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.audioManager?.PlayDangerCloseSound("nuke_detonate", targetPosition, is3D: false, "danger_close/nuke_explosion.wav", 1f); 5__1 = "Cartridge50mmFlareDangerClose"; if (!IM.OD.ContainsKey(5__1)) { <>4__this.logger.LogWarning((object)"Nuke cartridge not available - using fallback explosion"); return false; } 5__2 = IM.OD[5__1]; <>4__this.SpawnNukeExplosion(5__2, targetPosition, 0f); <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 2; return true; case 2: <>1__state = -1; 5__3 = 8; 5__4 = 5f; 5__7 = 0; while (5__7 < 5__3) { 5__8 = 360f / (float)5__3 * (float)5__7; 5__9 = new Vector3(Mathf.Sin(5__8 * ((float)Math.PI / 180f)) * 5__4, Random.Range(-1f, 2f), Mathf.Cos(5__8 * ((float)Math.PI / 180f)) * 5__4); <>4__this.SpawnNukeExplosion(5__2, targetPosition + 5__9, 0.05f * (float)5__7); 5__7++; } <>2__current = (object)new WaitForSeconds(0.3f); <>1__state = 3; return true; case 3: <>1__state = -1; 5__5 = 12; 5__6 = 10f; 5__10 = 0; while (5__10 < 5__5) { 5__11 = 360f / (float)5__5 * (float)5__10 + 15f; 5__12 = new Vector3(Mathf.Sin(5__11 * ((float)Math.PI / 180f)) * 5__6, Random.Range(-2f, 3f), Mathf.Cos(5__11 * ((float)Math.PI / 180f)) * 5__6); <>4__this.SpawnNukeExplosion(5__2, targetPosition + 5__12, 0.03f * (float)5__10); 5__10++; } <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 4; return true; case 4: <>1__state = -1; 5__13 = 0; while (5__13 < 5) { 5__14 = new Vector3(Random.Range(-3f, 3f), 5f + (float)5__13 * 2f, Random.Range(-3f, 3f)); <>4__this.SpawnNukeExplosion(5__2, targetPosition + 5__14, 0.1f * (float)5__13); 5__13++; } <>4__this.logger.LogInfo((object)"Nuke detonation complete - area devastated!"); <>4__this.audioManager?.PlayDangerCloseSound("nuke_aftermath", targetPosition, is3D: false, "danger_close/nuke_aftermath.wav", 0.8f); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__19 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Vector3 position; public float delay; public SpawnManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__19(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.audioManager?.PlayDangerCloseSound("explosion", position, is3D: true, "danger_close/explosion_impact.wav", 0.9f); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private H3TVRImproved plugin; private ManualLogSource logger; private AdvancedChatSosigSpawner advancedChatSpawner; private AudioManager audioManager; public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource, AdvancedChatSosigSpawner chatSpawnerInstance, AudioManager audioManagerInstance) { plugin = pluginInstance; logger = logSource; advancedChatSpawner = chatSpawnerInstance; audioManager = audioManagerInstance; OptionalDependencyManager.Initialize(logger); SosigWeaponEnhancer.Initialize(logger); logger.LogInfo((object)"[SpawnManager] Spawn manager initialized successfully"); if (OptionalDependencyManager.HasAnyDependencies()) { logger.LogInfo((object)$"[SpawnManager] Enhanced sosig spawning active with {OptionalDependencyManager.GetAvailableDependencyCount()} dependencies"); } } public void SpawnWonderfulToy() { //IL_000b: 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_0024: 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_003b: 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 + new Vector3(0f, 0.25f, 0f); audioManager?.PlayWondertoySound("before_spawn", position, is3D: true, "wondertoy/wondertoy_appear.wav"); SpawnObject("TippyToyAnton", "WonderToy"); audioManager?.PlayWondertoySound("after_spawn", position, is3D: true, "wondertoy/wondertoy_ready.wav"); } public void SpawnJeditToy() { //IL_000b: 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_0024: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) Vector3 val = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayWondertoySound("before_activate", val, is3D: true, "wondertoy/jedi_ignite.wav"); try { if (!ValidateSpawnConditions()) { return; } string text = "ftw.JediTippyToy"; if (!IM.OD.ContainsKey(text)) { logger.LogWarning((object)"Jedi Tippy Toy not available. Install: https://thunderstore.io/c/h3vr/p/PutterMyBancakes/Jeditippytoy/"); logger.LogInfo((object)("Expected Item ID: " + text)); logger.LogInfo((object)"Available Tippy Toy items:"); { foreach (KeyValuePair item in IM.OD) { if (item.Key.ToLower().Contains("tippy") || item.Key.ToLower().Contains("jedi")) { logger.LogInfo((object)(" - " + item.Key)); } } return; } } FVRObject val2 = IM.OD[text]; GameObject tippyToy = Object.Instantiate(((AnvilAsset)val2).GetGameObject(), val, GM.CurrentPlayerBody.Head.rotation); ((MonoBehaviour)this).StartCoroutine(FlipTippyToyToActivate(tippyToy)); logger.LogInfo((object)("Successfully spawned Jedi Tippy Toy (ID: " + text + ")")); audioManager?.PlayWondertoySound("after_activate", val, is3D: true, "wondertoy/jedi_ready.wav"); } catch (Exception ex) { logger.LogError((object)("SpawnJeditToy failed: " + ex.Message)); } } private IEnumerator FlipTippyToyToActivate(GameObject tippyToy) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__7(0) { <>4__this = this, tippyToy = tippyToy }; } public void SpawnHydration() { //IL_000b: 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_0024: 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_003b: 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 + new Vector3(0f, 0.25f, 0f); audioManager?.PlayHydrationSound("before_spawn", position, is3D: true, "hydration/bottle_materialize.wav"); SpawnObject("SuppressorBottle", "Hydration"); audioManager?.PlayHydrationSound("after_spawn", position, is3D: true, "hydration/bottle_ready.wav"); } public void SpawnPillow() { //IL_0020: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) try { if (!ValidateSpawnConditions()) { return; } Vector3 position = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); plugin.GetPillowConfig(out var min, out var max); int num = Random.Range(min, max + 1); logger.LogInfo((object)$"Spawning {num} pillow(s)"); audioManager?.PlayWondertoySound("before_pillow", position, is3D: true, "pillow/pillow_summon.wav", 0.8f); for (int i = 0; i < num; i++) { if (!IM.OD.ContainsKey("BodyPillow")) { logger.LogError((object)"BodyPillow not found in ObjectDictionary"); return; } FVRObject val = IM.OD["BodyPillow"]; Vector3 val2 = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); GameObject val3 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), val2, GM.CurrentPlayerBody.Head.rotation); Rigidbody component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddForce(GM.CurrentPlayerBody.Head.forward * 4000f); } } audioManager?.PlayWondertoySound("after_pillow", position, is3D: true, "pillow/pillow_launched.wav", 0.6f); HandlePillowEffects(); } catch (Exception ex) { logger.LogError((object)("SpawnPillow failed: " + ex.Message)); } } public void SpawnShuri() { //IL_0062: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ff: 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_0110: 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_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: 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) try { if (!ValidateSpawnConditions()) { return; } plugin.GetShurikenConfig(out var min, out var max); float shurikenScale = plugin.GetShurikenScale(); int num = Random.Range(min, max + 1); logger.LogInfo((object)$"Spawning {num} shuriken(s)"); Vector3 val = GM.CurrentPlayerBody.Head.position + GM.CurrentPlayerBody.Head.forward * 0.02f; audioManager?.PlayShurikenSound("before_throw", val, is3D: true, "shuriken/shuriken_prepare.wav", 0.9f); if (!IM.OD.ContainsKey("Shuriken")) { logger.LogError((object)"Shuriken not found in ObjectDictionary"); return; } FVRObject val2 = IM.OD["Shuriken"]; Quaternion val3 = Quaternion.LookRotation(GM.CurrentPlayerBody.Head.forward); for (int i = 0; i < num; i++) { GameObject val4 = Object.Instantiate(((AnvilAsset)val2).GetGameObject(), val, val3); val4.transform.localScale = new Vector3(shurikenScale, shurikenScale, shurikenScale); Rigidbody component = val4.GetComponent(); if ((Object)(object)component != (Object)null) { component.velocity = GM.CurrentPlayerBody.Head.forward * 30f; } Object.Destroy((Object)(object)val4, 60f); } audioManager?.PlayShurikenSound("after_throw", val, is3D: true, "shuriken/shuriken_thrown.wav", 0.7f); } catch (Exception ex) { logger.LogError((object)("SpawnShuri failed: " + ex.Message)); } } public void SpawnSkittySubGun() { //IL_000b: 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_0024: 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_003b: 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 + new Vector3(0f, 0.25f, 0f); audioManager?.PlayWeaponSpawnSound("before_spawn", position, is3D: true, "weapons/weapon_materializing.wav", 0.8f); SpawnObject("SkittySubGun", "SkittySubGun"); audioManager?.PlayWeaponSpawnSound("after_spawn", position, is3D: true, "weapons/weapon_ready.wav", 0.7f); } public void SpawnSkittyBigGun() { //IL_000b: 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_0024: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) Vector3 position = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayWeaponSpawnSound("before_big_spawn", position, is3D: true, "weapons/big_gun_materializing.wav", 0.9f); WeaponManager weaponManager = plugin.GetWeaponManager(); if ((Object)(object)weaponManager != (Object)null) { weaponManager.SpawnRandomGun(isBigGun: true); } audioManager?.PlayWeaponSpawnSound("after_big_spawn", position, is3D: true, "weapons/big_gun_ready.wav", 0.8f); } public void SpawnAirStrikeGrenade() { //IL_0020: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_017b: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) try { if (!ValidateSpawnConditions()) { return; } Vector3 val = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayDangerCloseSound("before_airstrike", val, is3D: true, "danger_close/airstrike_call.wav", 0.9f); string text = "JerryAr_AirStrikeSmokeGrenade"; if (!IM.OD.ContainsKey(text)) { logger.LogWarning((object)"Air Strike Smoke Grenade not available. Install: https://thunderstore.io/c/h3vr/p/JerryAr/AirStrikeSmokeGrenade/"); logger.LogInfo((object)("Expected Item ID: " + text)); logger.LogInfo((object)"Available grenade items:"); { foreach (KeyValuePair item in IM.OD) { if (item.Key.ToLower().Contains("grenade") || item.Key.ToLower().Contains("smoke") || item.Key.ToLower().Contains("airstrike")) { logger.LogInfo((object)(" - " + item.Key)); } } return; } } FVRObject val2 = IM.OD[text]; GameObject val3 = Object.Instantiate(((AnvilAsset)val2).GetGameObject(), val, GM.CurrentPlayerBody.Head.rotation); PinnedGrenade componentInChildren = val3.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.ReleaseLever(); logger.LogInfo((object)"Air Strike grenade pin pulled and lever released!"); } else { Component[] componentsInChildren = val3.GetComponentsInChildren(true); Component[] array = componentsInChildren; foreach (Component val4 in array) { if (!((Object)(object)val4 == (Object)null)) { Type type = ((object)val4).GetType(); MethodInfo method = type.GetMethod("ReleaseLever", BindingFlags.Instance | BindingFlags.Public); if ((object)method != null) { method.Invoke(val4, null); logger.LogInfo((object)("Air Strike grenade activated via " + type.Name + ".ReleaseLever()")); break; } MethodInfo method2 = type.GetMethod("Arm", BindingFlags.Instance | BindingFlags.Public); if ((object)method2 != null && method2.GetParameters().Length == 0) { method2.Invoke(val4, null); logger.LogInfo((object)("Air Strike grenade activated via " + type.Name + ".Arm()")); break; } } } } Rigidbody component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddForce(GM.CurrentPlayerBody.Head.forward * 500f); component.AddTorque(Random.insideUnitSphere * 2f); } logger.LogInfo((object)("Successfully spawned and armed Air Strike Smoke Grenade (ID: " + text + ")")); audioManager?.PlayDangerCloseSound("after_airstrike", val, is3D: true, "danger_close/airstrike_deployed.wav", 0.8f); } catch (Exception ex) { logger.LogError((object)("SpawnAirStrikeGrenade failed: " + ex.Message)); } } public void SpawnTitanMachine() { //IL_0020: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) try { if (!ValidateSpawnConditions()) { return; } Vector3 val = GM.CurrentPlayerBody.Head.position + GM.CurrentPlayerBody.Head.forward * 5f; audioManager?.PlayWeaponSpawnSound("before_titan", val, is3D: true, "weapons/titan_materializing.wav", 1f); string text = "JerryAr_TitanMachine"; if (!IM.OD.ContainsKey(text)) { logger.LogWarning((object)"Titan Machine not available. Install: https://thunderstore.io/c/h3vr/p/JerryAr/TitanMachine/"); logger.LogInfo((object)("Expected Item ID: " + text)); logger.LogInfo((object)"Available machine/titan items:"); { foreach (KeyValuePair item in IM.OD) { if (item.Key.ToLower().Contains("titan") || item.Key.ToLower().Contains("machine") || item.Key.ToLower().Contains("robot")) { logger.LogInfo((object)(" - " + item.Key)); } } return; } } FVRObject val2 = IM.OD[text]; Quaternion val3 = Quaternion.LookRotation(GM.CurrentPlayerBody.Head.forward); GameObject val4 = Object.Instantiate(((AnvilAsset)val2).GetGameObject(), val, val3); Sosig component = val4.GetComponent(); if ((Object)(object)component != (Object)null) { component.SetIFF(1); component.SetAssaultSpeed((SosigMoveSpeed)4); component.CommandAssaultPoint(GM.CurrentPlayerBody.Head.position); logger.LogInfo((object)"Titan Machine configured as hostile AI"); } else { logger.LogInfo((object)"Titan Machine spawned (no sosig component detected - may have custom AI)"); } logger.LogInfo((object)("Successfully spawned Titan Machine (ID: " + text + ")")); audioManager?.PlayWeaponSpawnSound("after_titan", val, is3D: true, "weapons/titan_active.wav", 0.9f); } catch (Exception ex) { logger.LogError((object)("SpawnTitanMachine failed: " + ex.Message)); } } public void SpawnNuke() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) try { if (ValidateSpawnConditions()) { Vector3 position = GM.CurrentPlayerBody.Head.position; Vector3 targetPosition = position + GM.CurrentPlayerBody.Head.forward * 15f; audioManager?.PlayDangerCloseSound("nuke_incoming", position, is3D: false, "danger_close/nuke_incoming.wav", 1f); logger.LogInfo((object)"NUKE INCOMING! Taking cover is advised..."); ((MonoBehaviour)this).StartCoroutine(NukeSequence(targetPosition)); } } catch (Exception ex) { logger.LogError((object)("SpawnNuke failed: " + ex.Message)); } } private IEnumerator NukeSequence(Vector3 targetPosition) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__16(0) { <>4__this = this, targetPosition = targetPosition }; } private void SpawnNukeExplosion(FVRObject explosiveObj, Vector3 position, float delay) { //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) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = Object.Instantiate(((AnvilAsset)explosiveObj).GetGameObject(), position, Random.rotation); Rigidbody component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.velocity = Random.insideUnitSphere * 5f; } FVRFireArmRound component2 = val.GetComponent(); if ((Object)(object)component2 != (Object)null) { TryExplodeCartridge(component2, delay); } } catch (Exception ex) { logger.LogWarning((object)("SpawnNukeExplosion failed: " + ex.Message)); } } public void DangerCloseBarrage() { //IL_0034: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_0108: 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_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) try { if (!ValidateSpawnConditions() || !IM.OD.ContainsKey("Cartridge50mmFlareDangerClose")) { return; } Vector3 position = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayDangerCloseSound("before_barrage", position, is3D: true, "danger_close/incoming_artillery.wav", 1f); plugin.GetDangerCloseConfig(out var min, out var max); int num = Random.Range(min, max + 1); logger.LogInfo((object)$"Spawning {num} danger close round(s)"); FVRObject val = IM.OD["Cartridge50mmFlareDangerClose"]; for (int i = 0; i < num; i++) { float num2 = 30f; float num3 = 2f; Vector2 insideUnitCircle = Random.insideUnitCircle; Vector3 val2 = GM.CurrentPlayerBody.Head.position + GM.CurrentPlayerBody.Head.forward * 0.02f; GameObject val3 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), val2, Quaternion.LookRotation(GM.CurrentPlayerBody.Head.forward)); val3.transform.Rotate(new Vector3(insideUnitCircle.x * num3, insideUnitCircle.y * num3, 0f), (Space)1); Rigidbody component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.velocity = val3.transform.forward * num2; } FVRFireArmRound component2 = val3.GetComponent(); if ((Object)(object)component2 != (Object)null) { TryExplodeCartridge(component2, 0.5f); ((MonoBehaviour)this).StartCoroutine(PlayDelayedExplosionSound(val2, 0.5f)); } } audioManager?.PlayDangerCloseSound("after_barrage", position, is3D: true, "danger_close/barrage_complete.wav", 0.8f); } catch (Exception ex) { logger.LogError((object)("DangerCloseBarrage failed: " + ex.Message)); } } private IEnumerator PlayDelayedExplosionSound(Vector3 position, float delay) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__19(0) { <>4__this = this, position = position, delay = delay }; } public void DestroyQuickbelt() { //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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) try { Vector3 position = GM.CurrentPlayerBody.Head.position; audioManager?.PlayDestructionSound("before_destroy", position, is3D: false, "destruction/quickbelt_clearing.wav", 0.7f); FVRQuickBeltSlot[] array = Object.FindObjectsOfType(); if (array == null || array.Length == 0) { logger.LogInfo((object)"No quickbelt slots found in scene."); return; } int num = 0; FVRQuickBeltSlot[] array2 = array; for (int i = 0; i < array2.Length; i++) { FVRPhysicalObject val = array2[i]?.CurObject; if (!((Object)(object)val == (Object)null) && !(val is FVRFireArmMagazine)) { val.SetQuickBeltSlot((FVRQuickBeltSlot)null); Object.Destroy((Object)(object)((Component)val).gameObject); num++; } } if (num > 0) { SpawnCelebratoryShell(); audioManager?.PlayDestructionSound("after_destroy", position, is3D: false, "destruction/quickbelt_cleared.wav", 0.6f); logger.LogInfo((object)$"Destroyed {num} quickbelt object(s) (magazines preserved)."); } else { logger.LogInfo((object)"No items in quickbelt to destroy (magazines excluded)."); } } catch (Exception ex) { logger.LogError((object)("DestroyQuickbelt failed: " + ex.Message)); } } public void SpawnChatSosigFriendly() { try { string text = "Player_" + Random.Range(1000, 9999); advancedChatSpawner?.SpawningSequence(text); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Spawned friendly chat sosig: " + text)); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to spawn friendly chat sosig: " + ex.Message)); } } } public void SpawnChatSosigEnemy() { try { string text = "Enemy_" + Random.Range(1000, 9999); advancedChatSpawner?.SpawningSequenceEnemy(1, text); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Spawned enemy chat sosig: " + text)); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to spawn enemy chat sosig: " + ex.Message)); } } } public void SpawnWarlordBoss(string twitchUsername = null) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) try { string text = ((!string.IsNullOrEmpty(twitchUsername)) ? ("?? " + twitchUsername.ToUpper() + " ??") : "?? WARLORD ??"); advancedChatSpawner?.SpawningSequenceWarlord(text); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Spawned WARLORD boss: " + text)); } AudioManager obj2 = audioManager; if (obj2 != null) { FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody; Vector3? obj3; if (currentPlayerBody == null) { obj3 = null; } else { Transform head = currentPlayerBody.Head; obj3 = ((head != null) ? new Vector3?(head.position) : null); } obj2.PlayDangerCloseSound("warlord_spawn", (Vector3)(((??)obj3) ?? Vector3.zero), is3D: false, "boss/warlord_appears.wav", 1f); } } catch (Exception ex) { ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogError((object)("Failed to spawn Warlord boss: " + ex.Message)); } } } public void ClearAllChatSosigs() { AdvancedChatSosigSpawner instance = AdvancedChatSosigSpawner.Instance; if ((Object)(object)instance != (Object)null) { instance.ClearAllSosigs(); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Cleared all chat sosigs and bosses"); } } else { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogWarning((object)"Advanced Chat Spawner not available"); } } } public ChatSosigStats GetChatSosigStats() { AdvancedChatSosigSpawner instance = AdvancedChatSosigSpawner.Instance; if ((Object)(object)instance != (Object)null) { AdvancedChatSosigSpawner.SosigStats stats = instance.GetStats(); return new ChatSosigStats { friendlyCount = stats.Allies, enemyCount = stats.Enemies, activeSosigCount = stats.TotalActive }; } return new ChatSosigStats { friendlyCount = 0, enemyCount = 0, activeSosigCount = 0 }; } private void SpawnObject(string itemID, string objectName) { //IL_0063: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) try { if (!ValidateSpawnConditions()) { return; } if (!IM.OD.ContainsKey(itemID)) { logger.LogError((object)("Item '" + itemID + "' not found in ObjectDictionary for " + objectName)); return; } FVRObject val = IM.OD[itemID]; Vector3 val2 = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); Quaternion rotation = GM.CurrentPlayerBody.Head.rotation; GameObject val3 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), val2, rotation); Rigidbody component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddTorque(new Vector3(0.25f, 0.25f, 0.25f)); component.AddForce(GM.CurrentPlayerBody.Head.forward * 25f); } logger.LogInfo((object)("Successfully spawned " + objectName)); } catch (Exception ex) { logger.LogError((object)("Failed to spawn " + objectName + ": " + ex.Message)); } } private void SpawnGrenade(string grenadeID, string grenadeName, float force, bool shouldArm) { //IL_0030: 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_0049: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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) try { if (!ValidateSpawnConditions() || !IM.OD.ContainsKey(grenadeID)) { return; } Vector3 val = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayDangerCloseSound("before_grenade", val, is3D: true, "grenades/pin_pull.wav", 0.8f); FVRObject val2 = IM.OD[grenadeID]; GameObject val3 = Object.Instantiate(((AnvilAsset)val2).GetGameObject(), val, GM.CurrentPlayerBody.Head.rotation); if (shouldArm) { PinnedGrenade componentInChildren = val3.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.ReleaseLever(); } } Rigidbody component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddForce(GM.CurrentPlayerBody.Head.forward * force); } audioManager?.PlayDangerCloseSound("after_grenade", val, is3D: true, "grenades/grenade_thrown.wav", 0.7f); logger.LogInfo((object)("Spawned " + grenadeName)); } catch (Exception ex) { logger.LogError((object)("Spawn" + grenadeName + " failed: " + ex.Message)); } } public void SpawnFlash() { //IL_000b: 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_0024: 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_003b: Unknown result type (might be due to invalid IL or missing references) Vector3 position = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayDangerCloseSound("before_flash", position, is3D: true, "grenades/flashbang_prepare.wav", 0.9f); SpawnGrenade("PinnedGrenadeXM84", "Flash", 500f, shouldArm: true); } public void SpawnFlash2() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) try { if (!ValidateSpawnConditions() || !IM.OD.ContainsKey("PinnedGrenadeXM84")) { return; } Vector3 position = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayDangerCloseSound("before_multiflash", position, is3D: true, "grenades/multiple_flashbang.wav", 1f); FVRObject val = IM.OD["PinnedGrenadeXM84"]; Vector3 val2 = default(Vector3); for (int i = 0; i < 4; i++) { float num = (float)i * 90f; ((Vector3)(ref val2))..ctor(Mathf.Sin(num * ((float)Math.PI / 180f)) * 0.3f, Random.Range(-0.1f, 0.2f), Mathf.Cos(num * ((float)Math.PI / 180f)) * 0.3f); Vector3 val3 = GM.CurrentPlayerBody.Head.position + GM.CurrentPlayerBody.Head.TransformDirection(val2) + new Vector3(0f, 0.25f, 0f); GameObject val4 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), val3, GM.CurrentPlayerBody.Head.rotation); val4.transform.Rotate(Random.Range(-15f, 15f), Random.Range(-15f, 15f), 0f); PinnedGrenade componentInChildren = val4.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.ReleaseLever(); } Vector3 val5 = GM.CurrentPlayerBody.Head.forward + new Vector3(Random.Range(-0.2f, 0.2f), Random.Range(-0.1f, 0.3f), Random.Range(-0.2f, 0.2f)); Rigidbody component = val4.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddForce(val5 * Random.Range(400f, 600f)); } } audioManager?.PlayDangerCloseSound("after_multiflash", position, is3D: true, "grenades/flashbangs_thrown.wav", 0.8f); logger.LogInfo((object)"Spawned Flash2 (4 flashbangs)"); } catch (Exception ex) { logger.LogError((object)("SpawnFlash2 failed: " + ex.Message)); } } public void SpawnNadeRain() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) try { if (Random.Range(1, 11) != 1 || !ValidateSpawnConditions() || !IM.OD.ContainsKey("PinnedGrenadeM67")) { return; } Vector3 position = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayDangerCloseSound("before_nade_rain", position, is3D: true, "grenades/grenade_incoming.wav", 0.8f); FVRObject val = IM.OD["PinnedGrenadeM67"]; float num = 15f; float num2 = 4f; Vector2 insideUnitCircle = Random.insideUnitCircle; int num3 = Random.Range(1, 20); Vector3 val2 = GM.CurrentPlayerBody.Head.position + GM.CurrentPlayerBody.Head.up * 0.02f; GameObject val3 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), val2, Quaternion.LookRotation(GM.CurrentPlayerBody.Head.up)); val3.transform.Rotate(new Vector3(insideUnitCircle.x * num2, insideUnitCircle.y * num2, 0f), (Space)1); Rigidbody component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.velocity = val3.transform.forward * num; } if (num3 == 10) { PinnedGrenade componentInChildren = val3.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.ReleaseLever(); } } logger.LogInfo((object)"Spawned NadeRain grenade"); } catch (Exception ex) { logger.LogError((object)("SpawnNadeRain failed: " + ex.Message)); } } public void DestroyHeld() { //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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) try { Vector3 position = GM.CurrentPlayerBody.RightHand.position; audioManager?.PlayDestructionSound("before_destroy_held", position, is3D: true, "destruction/item_dissolving.wav", 0.8f); FVRViveHand[] array = GM.CurrentMovementManager?.Hands; if (array == null || array.Length < 2) { logger.LogInfo((object)"No hands found or hand system not available."); return; } FVRViveHand val = array[1]; if ((Object)(object)((val != null) ? val.CurrentInteractable : null) != (Object)null && val.CurrentInteractable is FVRPhysicalObject) { Object.Destroy((Object)(object)((Component)val.CurrentInteractable).gameObject); SpawnCelebratoryShell(); audioManager?.PlayDestructionSound("after_destroy_held", position, is3D: true, "destruction/item_destroyed.wav", 0.7f); logger.LogInfo((object)"Destroyed held item in right hand."); } else { logger.LogInfo((object)"No item held in right hand to destroy."); } } catch (Exception ex) { logger.LogError((object)("DestroyHeld failed: " + ex.Message)); } } private void SpawnCelebratoryShell() { //IL_0035: 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_0045: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_0109: Unknown result type (might be due to invalid IL or missing references) try { if (IM.OD.ContainsKey("12GaugeShellFreedomfetti")) { FVRObject val = IM.OD["12GaugeShellFreedomfetti"]; float num = 4f; Vector2 insideUnitCircle = Random.insideUnitCircle; Vector3 val2 = GM.CurrentPlayerBody.RightHand.position + (GM.CurrentPlayerBody.RightHand.forward + GM.CurrentPlayerBody.RightHand.up * 0.5f) * 0.02f; GameObject val3 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), val2, Quaternion.LookRotation(GM.CurrentPlayerBody.RightHand.forward)); val3.transform.Rotate(new Vector3(insideUnitCircle.x * num, insideUnitCircle.y * num, 0f), (Space)1); FVRFireArmRound component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { TryExplodeCartridge(component, 0.01f); } audioManager?.PlayUISound("celebration", val2, "ui/celebration.wav", 0.6f); } } catch (Exception ex) { logger.LogError((object)("SpawnCelebratoryShell failed: " + ex.Message)); } } private void TryExplodeCartridge(FVRFireArmRound cartridge, float delay) { try { Type type = ((object)cartridge).GetType(); string[] array = new string[5] { "Splode", "Explode", "Detonate", "Fire", "Ignite" }; string[] array2 = array; foreach (string name in array2) { MethodInfo method = type.GetMethod(name, new Type[3] { typeof(float), typeof(bool), typeof(bool) }); if ((object)method != null) { method.Invoke(cartridge, new object[3] { delay, false, true }); return; } method = type.GetMethod(name, new Type[1] { typeof(float) }); if ((object)method != null) { method.Invoke(cartridge, new object[1] { delay }); return; } method = type.GetMethod(name, new Type[0]); if ((object)method != null) { method.Invoke(cartridge, null); return; } } logger.LogWarning((object)"Could not find explosion method for FVRFireArmRound"); } catch (Exception ex) { logger.LogWarning((object)("TryExplodeCartridge failed: " + ex.Message)); } } private bool ValidateSpawnConditions() { if ((Object)(object)GM.CurrentPlayerBody?.Head == (Object)null) { logger.LogWarning((object)"Cannot spawn: Player head reference is null"); return false; } if (IM.OD == null) { logger.LogWarning((object)"Cannot spawn: ItemManager ObjectDictionary is null"); return false; } return true; } private void HandlePillowEffects() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) plugin.GetPillowGrenadeConfig(out var enabled, out var chance, out var armedChance); plugin.GetPillowZeroGravityConfig(out var enabled2, out var chance2, out var duration); plugin.GetPillowSlomoConfig(out var enabled3, out var chance3, out var duration2); if (enabled && Random.value < chance) { logger.LogInfo((object)"Pillow grenade spawn triggered!"); audioManager?.PlayDangerCloseSound("pillow_grenade", GM.CurrentPlayerBody.Head.position, is3D: true, "pillow/grenade_surprise.wav", 0.8f); SpawnPillowGrenade(armedChance); } if (enabled2 && Random.value < chance2) { logger.LogInfo((object)$"Pillow zero gravity triggered! Duration: {duration}s"); audioManager?.PlaySlomoSound("zerog_start", GM.CurrentPlayerBody.Head.position, is3D: false, "effects/zero_gravity.wav", 0.7f); EffectsManager effectsManager = plugin.GetEffectsManager(); if (effectsManager != null) { ((MonoBehaviour)effectsManager).StartCoroutine(effectsManager.ActivatePillowZeroGravity(duration)); } } if (enabled3 && Random.value < chance3) { logger.LogInfo((object)$"Pillow slow motion triggered! Duration: {duration2}s"); audioManager?.PlaySlomoSound("start", GM.CurrentPlayerBody.Head.position, is3D: false, "effects/slomo_pillow.wav", 0.8f); EffectsManager effectsManager2 = plugin.GetEffectsManager(); if (effectsManager2 != null) { ((MonoBehaviour)effectsManager2).StartCoroutine(effectsManager2.ActivatePillowSlomo(duration2)); } } } private void SpawnPillowGrenade(float armedChance) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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) try { if (!IM.OD.ContainsKey("PinnedGrenadeM67")) { logger.LogError((object)"PinnedGrenadeM67 not found for pillow grenade"); return; } FVRObject val = IM.OD["PinnedGrenadeM67"]; Vector3 val2 = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); GameObject val3 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), val2, GM.CurrentPlayerBody.Head.rotation); if (Random.value < armedChance) { PinnedGrenade componentInChildren = val3.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.ReleaseLever(); logger.LogInfo((object)$"Pillow grenade armed and released! ({armedChance * 100f}% chance triggered)"); } } else { logger.LogInfo((object)"Pillow grenade spawned but not armed (safe)"); } Rigidbody component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddForce(GM.CurrentPlayerBody.Head.forward * 4000f); component.AddTorque(Random.insideUnitSphere * 5f); } } catch (Exception ex) { logger.LogError((object)("SpawnPillowGrenade failed: " + ex.Message)); } } } public class PillowGrenade : MonoBehaviour { [CompilerGenerated] private sealed class d__3 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PillowGrenade <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(<>4__this.fuseTime); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.Explode(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private bool isArmed; private float fuseTime = 3f; public void Initialize(bool armed) { isArmed = armed; if (isArmed) { ((MonoBehaviour)this).StartCoroutine(FuseCoroutine()); } } private IEnumerator FuseCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(0) { <>4__this = this }; } private void Explode() { //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_000d: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0066: 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_0091: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)this).transform.position; Collider[] array = Physics.OverlapSphere(position, 5f); Collider[] array2 = array; foreach (Collider val in array2) { Rigidbody component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { Vector3 val2 = ((Component)val).transform.position - position; Vector3 normalized = ((Vector3)(ref val2)).normalized; float num = Vector3.Distance(position, ((Component)val).transform.position); float num2 = Mathf.Lerp(10f, 0f, num / 5f); component.AddForce(normalized * num2, (ForceMode)1); } } Object.Destroy((Object)(object)((Component)this).gameObject); } } public class PillowZeroGravity : MonoBehaviour { [CompilerGenerated] private sealed class d__3 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PillowZeroGravity <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; Physics.gravity = Vector3.zero; <>2__current = (object)new WaitForSeconds(<>4__this.duration); <>1__state = 1; return true; case 1: <>1__state = -1; Physics.gravity = new Vector3(0f, <>4__this.originalGravity, 0f); Object.Destroy((Object)(object)<>4__this); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private float duration; private float originalGravity; public void Initialize(float dur) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) duration = dur; originalGravity = Physics.gravity.y; ((MonoBehaviour)this).StartCoroutine(ZeroGravityCoroutine()); } private IEnumerator ZeroGravityCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(0) { <>4__this = this }; } } public class PillowSlomo : MonoBehaviour { [CompilerGenerated] private sealed class d__2 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public EffectsManager effectsManager; public PillowSlomo <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)effectsManager != (Object)null) { <>2__current = ((MonoBehaviour)effectsManager).StartCoroutine(effectsManager.ActivatePillowSlomo(<>4__this.duration)); <>1__state = 1; return true; } break; case 1: <>1__state = -1; break; } Object.Destroy((Object)(object)<>4__this); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private float duration; public void Initialize(float dur, EffectsManager effects) { duration = dur; ((MonoBehaviour)this).StartCoroutine(SlomoCoroutine(effects)); } private IEnumerator SlomoCoroutine(EffectsManager effectsManager) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(0) { <>4__this = this, effectsManager = effectsManager }; } } public class MagazineCompatibilityScore { public FVRObject magazine; public int score; } public class WeaponManager : MonoBehaviour { private class ScaleModifierData { public Vector3 originalScale; public float endTime; public float targetScale; } private H3TVRImproved plugin; private ManualLogSource logger; private AudioManager audioManager; private int weaponSpawnCount = 0; private float lastWeaponSpawnTime = 0f; private Dictionary activeScaleModifiers = new Dictionary(); public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource, AudioManager audioManagerInstance) { plugin = pluginInstance; logger = logSource; audioManager = audioManagerInstance; OptionalDependencyManager.Initialize(logger); InitializeWeaponData(); logger.LogInfo((object)"[WeaponManager] Weapon manager initialized successfully"); if (OptionalDependencyManager.HasAnyDependencies()) { logger.LogInfo((object)$"[WeaponManager] Enhanced with {OptionalDependencyManager.GetAvailableDependencyCount()} optional dependencies"); } else { logger.LogInfo((object)"[WeaponManager] Running in standard mode - install optional dependencies for enhanced features"); } } private void SpawnSkittyGunFromLists(bool isBigGun) { try { plugin.GetGunLists(out string gunListValue, out string _); string listString = (File.Exists(gunListValue) ? File.ReadAllText(gunListValue) : gunListValue); string[] array = ParseConfigList(listString); if (array.Length == 0) { logger.LogError((object)"Gun list is empty after parsing."); return; } string text = (isBigGun ? array[0] : array[Random.Range(0, array.Length)]); if (!IM.OD.ContainsKey(text)) { logger.LogError((object)("Gun key '" + text + "' not found in IM.OD dictionary.")); return; } FVRObject gunObj = IM.OD[text]; SpawnGunAndMagazine(gunObj, isBigGun); } catch (Exception ex) { logger.LogError((object)("SpawnSkittyGunFromLists failed: " + ex.Message)); } } private void InitializeWeaponData() { try { weaponSpawnCount = 0; lastWeaponSpawnTime = 0f; logger.LogInfo((object)"[WeaponManager] Weapon data initialized"); } catch (Exception ex) { logger.LogError((object)("[WeaponManager] Error initializing weapon data: " + ex.Message)); } } public void SpawnRandomGun(bool isBigGun) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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) try { if (ValidateSpawnConditions()) { Vector3 position = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); audioManager?.PlayWeaponSpawnSound(isBigGun ? "gun_spawn" : "skitty_sub_gun", position); if (plugin.UseItemManagerForGuns()) { SpawnFromItemManager(isBigGun); } else { SpawnFromConfigLists(isBigGun); } } } catch (Exception ex) { logger.LogError((object)("SpawnRandomGun failed: " + ex.Message)); } } public void SpawnSkittySubGun() { try { if (ValidateSpawnConditions()) { logger.LogInfo((object)"SpawnSkittySubGun: Using original list-based system"); SpawnSkittyGunFromLists(isBigGun: false); } } catch (Exception ex) { logger.LogError((object)("SpawnSkittySubGun failed: " + ex.Message)); } } public void SpawnSkittyBigGun() { try { if (ValidateSpawnConditions()) { logger.LogInfo((object)"SpawnSkittyBigGun: Using original list-based system"); SpawnSkittyGunFromLists(isBigGun: true); } } catch (Exception ex) { logger.LogError((object)("SpawnSkittyBigGun failed: " + ex.Message)); } } private void SpawnFromItemManager(bool isBigGun) { FVRObject[] array = IM.OD.Values.Where((FVRObject obj) => (Object)(object)obj != (Object)null && (int)obj.Category == 1).ToArray(); if (array.Length == 0) { logger.LogError((object)"No firearms found in ItemManager."); return; } FVRObject val; if (isBigGun && array.Length != 0) { val = array[0]; logger.LogInfo((object)("Selected first gun for big gun mode: " + val.DisplayName)); } else { val = array[Random.Range(0, array.Length)]; logger.LogInfo((object)("Randomly selected gun: " + val.DisplayName)); } SpawnGunAndMagazine(val, isBigGun); } private void SpawnFromConfigLists(bool isBigGun) { plugin.GetGunLists(out string gunListValue, out string _); string listString = (File.Exists(gunListValue) ? File.ReadAllText(gunListValue) : gunListValue); string[] array = ParseConfigList(listString); if (array.Length == 0) { logger.LogError((object)"Gun list is empty after parsing."); return; } string text = (isBigGun ? array[0] : array[Random.Range(0, array.Length)]); if (!IM.OD.ContainsKey(text)) { logger.LogError((object)("Gun key '" + text + "' not found in IM.OD dictionary.")); return; } FVRObject gunObj = IM.OD[text]; SpawnGunAndMagazine(gunObj, isBigGun); } private void SpawnGunAndMagazine(FVRObject gunObj, bool isBigGun) { //IL_000b: 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_0024: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_00b2: Unknown result type (might be due to invalid IL or missing references) Vector3 val = GM.CurrentPlayerBody.Head.position + new Vector3(0f, 0.25f, 0f); GameObject val2 = Object.Instantiate(((AnvilAsset)gunObj).GetGameObject(), val, GM.CurrentPlayerBody.Head.rotation); Rigidbody component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddTorque(new Vector3(0.25f, 0.25f, 0.25f)); component.AddForce(GM.CurrentPlayerBody.Head.forward * 100f); } if (isBigGun) { val2.transform.localScale = new Vector3(5f, 5f, 5f); } TrySpawnMatchingMagazine(gunObj, val, isBigGun); logger.LogInfo((object)("Spawned " + (isBigGun ? "big" : "normal") + " gun: " + gunObj.DisplayName)); } private void TrySpawnMatchingMagazine(FVRObject gunObj, Vector3 spawnPos, bool isBigGun) { //IL_01a0: Unknown result type (might be due to invalid IL or missing references) try { FVRObject val = null; GameObject gameObject = ((AnvilAsset)gunObj).GetGameObject(); FVRFireArm val2 = ((gameObject != null) ? gameObject.GetComponent() : null); if ((Object)(object)val2 != (Object)null && HasCompatibleMagazines(val2)) { List compatibleMagazines = GetCompatibleMagazines(val2); if (compatibleMagazines.Count > 0) { FVRObject val3 = compatibleMagazines[Random.Range(0, compatibleMagazines.Count)]; val = val3; logger.LogInfo((object)("Using built-in compatible magazine: " + val3.DisplayName)); } } if ((Object)(object)val == (Object)null) { val = FindBestMagazineMatchAdvanced(gunObj); if ((Object)(object)val != (Object)null) { logger.LogInfo((object)("Using advanced MagazinePatcher compatibility: " + val.DisplayName)); } } if ((Object)(object)val == (Object)null && !plugin.UseItemManagerForGuns()) { val = FindMagazineFromConfigLists(gunObj); if ((Object)(object)val != (Object)null) { logger.LogInfo((object)("Using config file magazine matching: " + val.DisplayName)); } } if ((Object)(object)val == (Object)null) { FVRObject[] array = IM.OD.Values.Where((FVRObject obj) => (Object)(object)obj != (Object)null && (int)obj.Category == 2).ToArray(); if (array.Length != 0) { val = array[Random.Range(0, array.Length)]; logger.LogInfo((object)("Using random magazine fallback: " + val.DisplayName)); } } if ((Object)(object)val != (Object)null) { SpawnMagazine(val, spawnPos, isBigGun); logger.LogInfo((object)("Successfully spawned magazine: " + val.DisplayName + " for gun: " + gunObj.DisplayName)); } else { logger.LogWarning((object)("Could not find any compatible magazine for gun: " + gunObj.DisplayName)); } } catch (Exception ex) { logger.LogError((object)("Magazine spawn failed: " + ex.Message)); } } private bool HasCompatibleMagazines(FVRFireArm firearm) { try { PropertyInfo property = ((object)firearm).GetType().GetProperty("CompatibleMagazines"); if ((object)property != null) { return property.GetValue(firearm, null) is IList list && list.Count > 0; } return false; } catch { return false; } } private List GetCompatibleMagazines(FVRFireArm firearm) { try { PropertyInfo property = ((object)firearm).GetType().GetProperty("CompatibleMagazines"); if ((object)property != null && property.GetValue(firearm, null) is IList source) { return source.Cast().ToList(); } return new List(); } catch { return new List(); } } private FVRObject FindBestMagazineMatchAdvanced(FVRObject gunObj) { //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Invalid comparison between Unknown and I4 if (OptionalDependencyManager.IsMagazinePatcherAvailable) { try { FVRObject val = OptionalDependencyManager.FindCompatibleMagazine(gunObj); if ((Object)(object)val != (Object)null) { logger.LogInfo((object)("[WeaponManager] Found magazine via Magazine Patcher: " + val.ItemID)); return val; } List enhancedMagazineCompatibility = OptionalDependencyManager.GetEnhancedMagazineCompatibility(gunObj); if (enhancedMagazineCompatibility.Count > 0) { FVRObject val2 = enhancedMagazineCompatibility[Random.Range(0, enhancedMagazineCompatibility.Count)]; logger.LogInfo((object)("[WeaponManager] Found magazine from enhanced compatibility: " + val2.ItemID)); return val2; } } catch (Exception ex) { logger.LogError((object)("[WeaponManager] Error using Magazine Patcher: " + ex.Message)); } } try { GameObject gameObject = ((AnvilAsset)gunObj).GetGameObject(); FVRFireArm val3 = ((gameObject != null) ? gameObject.GetComponent() : null); if ((Object)(object)val3 != (Object)null && HasCompatibleMagazines(val3)) { List compatibleMagazines = GetCompatibleMagazines(val3); if (compatibleMagazines.Count > 0) { FVRObject val4 = compatibleMagazines[Random.Range(0, compatibleMagazines.Count)]; logger.LogInfo((object)("[WeaponManager] Found magazine via H3VR CompatibleMagazines: " + val4.ItemID)); return val4; } } } catch (Exception ex2) { logger.LogWarning((object)("[WeaponManager] Could not access H3VR CompatibleMagazines: " + ex2.Message)); } if (IM.OD == null) { return null; } FVRObject val5 = null; float num = 0f; string gunId = gunObj.ItemID.ToLower(); string gunBase = ExtractGunBaseName(gunId); string gunCaliber = ExtractCaliber(gunId); foreach (KeyValuePair item in IM.OD) { FVRObject value = item.Value; if ((int)value.Category == 2) { string magId = value.ItemID.ToLower(); float num2 = CalculateCompatibilityScore(gunId, magId, gunBase, gunCaliber); if (num2 > num) { num = num2; val5 = value; } } } if ((Object)(object)val5 != (Object)null) { logger.LogInfo((object)$"[WeaponManager] Found magazine via advanced scoring: {val5.ItemID} (score: {num:F2})"); } return val5; } private string ExtractGunBaseName(string gunId) { try { string input = gunId.ToLower(); input = Regex.Replace(input, "[0-9]+", ""); input = input.Replace("_", "").Replace("-", ""); if (input.Length > 5) { input = input.Substring(0, 5); } return input; } catch { return (gunId.Length > 3) ? gunId.Substring(0, 3) : gunId; } } private string ExtractCaliber(string gunId) { try { string[] array = new string[8] { "9mm", "45acp", "762", "556", "308", "50bmg", "12ga", "20ga" }; string[] array2 = array; foreach (string text in array2) { if (gunId.ToLower().Contains(text)) { return text; } } return ""; } catch { return ""; } } private float CalculateCompatibilityScore(string gunId, string magId, string gunBase, string gunCaliber) { try { float num = 0f; if (!string.IsNullOrEmpty(gunBase) && magId.Contains(gunBase)) { num += 50f; } if (!string.IsNullOrEmpty(gunCaliber) && magId.Contains(gunCaliber)) { num += 30f; } if (gunId.Length >= 3 && magId.StartsWith(gunId.Substring(0, 3))) { num += 20f; } return num; } catch { return 0f; } } public void RandomizeHeldGun() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_00b4: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) try { FVRFireArm heldFirearm = GetHeldFirearm(); if ((Object)(object)heldFirearm == (Object)null) { logger.LogWarning((object)"RandomizeHeldGun: No firearm found in hands"); return; } Vector3 position = ((Component)heldFirearm).transform.position; Quaternion rotation = ((Component)heldFirearm).transform.rotation; string currentKey = ((FVRPhysicalObject)heldFirearm).ObjectWrapper?.ItemID; Object.Destroy((Object)(object)((Component)heldFirearm).gameObject); FVRObject[] array = IM.OD.Values.Where((FVRObject obj) => (Object)(object)obj != (Object)null && (int)obj.Category == 1 && obj.ItemID != currentKey).ToArray(); if (array.Length != 0) { FVRObject val = array[Random.Range(0, array.Length)]; GameObject val2 = Object.Instantiate(((AnvilAsset)val).GetGameObject(), position, rotation); Rigidbody component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { component.velocity = Vector3.zero; component.angularVelocity = Vector3.zero; } logger.LogInfo((object)("Randomized held gun to: " + val.DisplayName)); } } catch (Exception ex) { logger.LogError((object)("RandomizeHeldGun failed: " + ex.Message)); } } public void ToggleHeldGunFireMode() { //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) try { FVRFireArm heldFirearm = GetHeldFirearm(); if ((Object)(object)heldFirearm == (Object)null) { logger.LogWarning((object)"ToggleHeldGunFireMode: No firearm found in hands"); audioManager?.PlayUISound("error"); return; } string name = ((object)heldFirearm).GetType().Name; logger.LogInfo((object)("ToggleHeldGunFireMode: Attempting to toggle fire mode on " + name)); audioManager?.PlayWeaponSpawnSound("weapon_ready", ((Component)heldFirearm).transform.position); string[] array = new string[7] { "CycleFireMode", "CycleFireSelector", "ToggleFireMode", "NextFireMode", "CycleSelectorMode", "AdvanceFireSelector", "SwitchFireMode" }; string[] array2 = array; foreach (string text in array2) { MethodInfo method = ((object)heldFirearm).GetType().GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)method != null && method.GetParameters().Length == 0) { method.Invoke(heldFirearm, null); logger.LogInfo((object)("ToggleHeldGunFireMode: Successfully toggled via method '" + text + "'")); audioManager?.PlayUISound(); return; } } TryToggleFireSelectorField(heldFirearm); } catch (Exception ex) { logger.LogError((object)("ToggleHeldGunFireMode failed: " + ex.Message)); audioManager?.PlayUISound("error"); } } private void TryToggleFireSelectorField(FVRFireArm firearm) { string[] array = new string[7] { "m_fireSelector", "FireSelector", "m_selector", "fireSelector", "m_FireSelector", "m_fireSelectorMode", "FireSelectorMode" }; string[] array2 = array; foreach (string text in array2) { FieldInfo field = ((object)firearm).GetType().GetField(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)field != null && field.FieldType.IsEnum && TryToggleEnumField(firearm, field, text)) { logger.LogInfo((object)("ToggleHeldGunFireMode: Successfully toggled via field '" + text + "'")); return; } } logger.LogWarning((object)("ToggleHeldGunFireMode: Could not find fire mode control for " + ((object)firearm).GetType().Name)); } private bool TryToggleEnumField(FVRFireArm firearm, FieldInfo field, string fieldName) { try { object value = field.GetValue(firearm); if (value == null) { return false; } Array values = Enum.GetValues(value.GetType()); if (values.Length <= 1) { return false; } int num = Array.IndexOf(values, value); int index = (num + 1) % values.Length; object value2 = values.GetValue(index); field.SetValue(firearm, value2); logger.LogInfo((object)$"ToggleHeldGunFireMode: Changed {fieldName} from {value} to {value2}"); return true; } catch (Exception ex) { logger.LogWarning((object)("TryToggleEnumField failed for " + fieldName + ": " + ex.Message)); return false; } } public void EmptyHeldGunChamber() { try { FVRFireArm heldFirearm = GetHeldFirearm(); if ((Object)(object)heldFirearm == (Object)null) { logger.LogWarning((object)"EmptyHeldGunChamber: No firearm found in hands"); return; } string name = ((object)heldFirearm).GetType().Name; logger.LogInfo((object)("EmptyHeldGunChamber: Attempting to empty chamber on " + name)); string[] array = new string[8] { "EjectChamberedRound", "EjectRound", "EjectChambered", "Eject", "ExtractRound", "DumpChamber", "ClearChamber", "EmptyChamber" }; string[] array2 = array; foreach (string text in array2) { MethodInfo method = ((object)heldFirearm).GetType().GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)method != null && method.GetParameters().Length == 0) { method.Invoke(heldFirearm, null); logger.LogInfo((object)("EmptyHeldGunChamber: Successfully ejected via method '" + text + "'")); return; } } logger.LogWarning((object)("EmptyHeldGunChamber: Could not find chamber eject method for " + name)); } catch (Exception ex) { logger.LogError((object)("EmptyHeldGunChamber failed: " + ex.Message)); } } private FVRFireArm GetHeldFirearm() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown FVRViveHand[] array = GM.CurrentMovementManager?.Hands; if (array == null || array.Length == 0) { return null; } for (int num = array.Length - 1; num >= 0; num--) { FVRViveHand val = array[num]; if (!((Object)(object)((val != null) ? val.CurrentInteractable : null) == (Object)null)) { FVRInteractiveObject currentInteractable = val.CurrentInteractable; FVRFireArm val2 = (FVRFireArm)(object)((currentInteractable is FVRFireArm) ? currentInteractable : null); if ((Object)(object)val2 != (Object)null) { return val2; } if (((object)val.CurrentInteractable).GetType().IsSubclassOf(typeof(FVRFireArm))) { return (FVRFireArm)val.CurrentInteractable; } } } return null; } public void ActivateMalfunctionBoost(ref bool isActive, ref float endTime) { isActive = true; endTime = Time.time + 120f; logger.LogInfo((object)"Meatyceiver malfunction boost activated for 120 seconds."); } public void ApplyMalfunctionLogic() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown try { FVRViveHand[] array = GM.CurrentMovementManager?.Hands; if (array == null) { return; } FVRViveHand[] array2 = array; foreach (FVRViveHand val in array2) { if (!((Object)(object)((val != null) ? val.CurrentInteractable : null) == (Object)null)) { FVRInteractiveObject currentInteractable = val.CurrentInteractable; FVRFireArm val2 = (FVRFireArm)(object)((currentInteractable is FVRFireArm) ? currentInteractable : null); if ((Object)(object)val2 == (Object)null && ((object)val.CurrentInteractable).GetType().IsSubclassOf(typeof(FVRFireArm))) { val2 = (FVRFireArm)val.CurrentInteractable; } if (!((Object)(object)val2 == (Object)null) && IsMeatyWeapon(val2) && val.Input.TriggerDown && Random.value < 0.75f) { ForceMalfunction(val2); } } } } catch (Exception ex) { logger.LogError((object)("ApplyMalfunctionLogic failed: " + ex.Message)); } } private bool IsMeatyWeapon(FVRFireArm firearm) { try { string text = ((FVRPhysicalObject)firearm).ObjectWrapper?.ItemID ?? string.Empty; GameObject gameObject = ((Component)firearm).gameObject; string text2 = ((gameObject != null) ? ((Object)gameObject).name : null) ?? string.Empty; return text.IndexOf("meaty", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("meaty", StringComparison.OrdinalIgnoreCase) >= 0; } catch { return false; } } private void ForceMalfunction(FVRFireArm firearm) { try { string[] array = new string[5] { "ForceMalfunction", "DoMalfunction", "AttemptMalfunction", "Jam", "CauseMalfunction" }; string[] array2 = array; foreach (string text in array2) { MethodInfo method = ((object)firearm).GetType().GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)method != null && method.GetParameters().Length == 0) { method.Invoke(firearm, null); logger.LogInfo((object)("Forced malfunction via method: " + text)); return; } } string[] array3 = new string[4] { "MalfunctionChance", "m_malfunctionChance", "JamChance", "m_jamChance" }; string[] array4 = array3; foreach (string text2 in array4) { FieldInfo field = ((object)firearm).GetType().GetField(text2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)field != null && ((object)field.FieldType == typeof(float) || (object)field.FieldType == typeof(double))) { if ((object)field.FieldType == typeof(float)) { field.SetValue(firearm, 1f); } else { field.SetValue(firearm, 1.0); } logger.LogInfo((object)("Set high malfunction/jam chance via field: " + text2)); break; } } } catch (Exception ex) { logger.LogError((object)("ForceMalfunction reflection failed: " + ex.Message)); } } private FVRObject FindMagazineFromConfigLists(FVRObject gunObj) { try { plugin.GetGunLists(out string _, out string magListValue); string listString = (File.Exists(magListValue) ? File.ReadAllText(magListValue) : magListValue); string[] array = ParseConfigList(listString); if (array.Length == 0) { return null; } string gunTruncated = new string(gunObj.ItemID.Take(5).ToArray()); string[] array2 = array.Where((string m) => m.Contains(gunTruncated)).ToArray(); if (array2.Length != 0) { string key = array2[Random.Range(0, array2.Length)]; if (IM.OD.ContainsKey(key)) { return IM.OD[key]; } } return null; } catch (Exception ex) { logger.LogError((object)("FindMagazineFromConfigLists failed: " + ex.Message)); return null; } } private void SpawnMagazine(FVRObject magObj, Vector3 spawnPos, bool isBigGun) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = Object.Instantiate(((AnvilAsset)magObj).GetGameObject(), spawnPos, GM.CurrentPlayerBody.Head.rotation); Rigidbody component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddTorque(new Vector3(0.25f, 0.25f, 0.25f)); component.AddForce(GM.CurrentPlayerBody.Head.forward * 100f); } if (isBigGun) { val.transform.localScale = new Vector3(5f, 5f, 5f); } } catch (Exception ex) { logger.LogError((object)("SpawnMagazine failed: " + ex.Message)); } } private bool ValidateSpawnConditions() { return true; } private string[] ParseConfigList(string listString) { if (string.IsNullOrEmpty(listString)) { return new string[0]; } return (from s in listString.Split(new char[3] { ',', '\n', ';' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim()).ToArray(); } public void ScaleHeldWeapon(float scaleFactor, float duration = 30f) { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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) try { FVRFireArm heldFirearm = GetHeldFirearm(); if ((Object)(object)heldFirearm == (Object)null) { logger.LogWarning((object)"ScaleHeldWeapon: No firearm found in hands"); audioManager?.PlayUISound("error"); return; } if (activeScaleModifiers.ContainsKey(heldFirearm)) { RestoreOriginalScale(heldFirearm); } ScaleModifierData scaleModifierData = new ScaleModifierData { originalScale = ((Component)heldFirearm).transform.localScale, endTime = Time.time + duration, targetScale = scaleFactor }; activeScaleModifiers[heldFirearm] = scaleModifierData; ((Component)heldFirearm).transform.localScale = scaleModifierData.originalScale * scaleFactor; logger.LogInfo((object)$"ScaleHeldWeapon: Scaled {((Object)heldFirearm).name} to {scaleFactor}x for {duration} seconds"); audioManager?.PlayWeaponSpawnSound("weapon_ready", ((Component)heldFirearm).transform.position); audioManager?.PlayUISound(); } catch (Exception ex) { logger.LogError((object)("ScaleHeldWeapon failed: " + ex.Message)); audioManager?.PlayUISound("error"); } } public void RandomScaleHeldWeapon(float duration = 30f) { try { float[] array = new float[7] { 0.25f, 0.5f, 0.75f, 1.5f, 2f, 2.5f, 3f }; float num = array[Random.Range(0, array.Length)]; ScaleHeldWeapon(num, duration); string arg = ((num < 1f) ? "tiny" : ((num > 2f) ? "giant" : "enlarged")); logger.LogInfo((object)$"RandomScaleHeldWeapon: Applied {arg} scale ({num}x)"); } catch (Exception ex) { logger.LogError((object)("RandomScaleHeldWeapon failed: " + ex.Message)); } } public void MakeHeldWeaponTiny(float duration = 30f) { ScaleHeldWeapon(0.25f, duration); } public void MakeHeldWeaponGiant(float duration = 30f) { ScaleHeldWeapon(3f, duration); } public void RestoreHeldWeaponScale() { //IL_0066: 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) try { FVRFireArm heldFirearm = GetHeldFirearm(); if ((Object)(object)heldFirearm == (Object)null) { logger.LogWarning((object)"RestoreHeldWeaponScale: No firearm found in hands"); } else if (RestoreOriginalScale(heldFirearm)) { logger.LogInfo((object)("RestoreHeldWeaponScale: Restored original scale for " + ((Object)heldFirearm).name)); audioManager?.PlayUISound(); } else { logger.LogWarning((object)"RestoreHeldWeaponScale: No active scale modifier found"); } } catch (Exception ex) { logger.LogError((object)("RestoreHeldWeaponScale failed: " + ex.Message)); } } public void UpdateScaleModifiers() { //IL_012a: Unknown result type (might be due to invalid IL or missing references) try { if (activeScaleModifiers.Count == 0) { return; } List list = new List(); foreach (KeyValuePair activeScaleModifier in activeScaleModifiers) { FVRFireArm key = activeScaleModifier.Key; ScaleModifierData value = activeScaleModifier.Value; if (Time.time >= value.endTime) { list.Add(key); } else if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null) { list.Add(key); } } foreach (FVRFireArm item in list) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { RestoreOriginalScale(item); logger.LogInfo((object)("UpdateScaleModifiers: Scale modifier expired for " + ((Object)item).name)); audioManager?.PlayWeaponSpawnSound("weapon_ready", ((Component)item).transform.position, is3D: false); } else { activeScaleModifiers.Remove(item); } } } catch (Exception ex) { logger.LogError((object)("UpdateScaleModifiers failed: " + ex.Message)); } } private bool RestoreOriginalScale(FVRFireArm firearm) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)firearm == (Object)null || !activeScaleModifiers.ContainsKey(firearm)) { return false; } ScaleModifierData scaleModifierData = activeScaleModifiers[firearm]; ((Component)firearm).transform.localScale = scaleModifierData.originalScale; activeScaleModifiers.Remove(firearm); return true; } catch (Exception ex) { logger.LogError((object)("RestoreOriginalScale failed: " + ex.Message)); return false; } } public void ClearAllScaleModifiers() { try { List list = new List(activeScaleModifiers.Keys); foreach (FVRFireArm item in list) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { RestoreOriginalScale(item); } } activeScaleModifiers.Clear(); logger.LogInfo((object)"ClearAllScaleModifiers: Cleared all active scale modifiers"); } catch (Exception ex) { logger.LogError((object)("ClearAllScaleModifiers failed: " + ex.Message)); } } public float GetHeldWeaponScaleRemainingTime() { try { FVRFireArm heldFirearm = GetHeldFirearm(); if ((Object)(object)heldFirearm == (Object)null || !activeScaleModifiers.ContainsKey(heldFirearm)) { return 0f; } ScaleModifierData scaleModifierData = activeScaleModifiers[heldFirearm]; return Mathf.Max(0f, scaleModifierData.endTime - Time.time); } catch { return 0f; } } public bool IsHeldWeaponScaled() { try { FVRFireArm heldFirearm = GetHeldFirearm(); return (Object)(object)heldFirearm != (Object)null && activeScaleModifiers.ContainsKey(heldFirearm); } catch { return false; } } } public class AdvancedChatSosigSpawner : MonoBehaviour { public struct SosigStats { public int Allies; public int Enemies; public int Queued; public int TotalActive; public bool ChatWatcherActive; } [CompilerGenerated] private sealed class d__42 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AdvancedChatSosigSpawner <>4__this; private WaitForSeconds 5__1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__42(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = new WaitForSeconds(10f); break; case 1: <>1__state = -1; <>4__this.CleanupDeadSosigs(); break; } <>2__current = 5__1; <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__29 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AdvancedChatSosigSpawner <>4__this; private float 5__1; private float 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__29(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = 10f; 5__2 = 0f; goto IL_007a; case 1: <>1__state = -1; 5__2 += 0.5f; goto IL_007a; case 2: { <>1__state = -1; <>4__this.templateCache.BuildCache(<>4__this.config.allyPoolIDs, <>4__this.config.enemyPoolIDs); ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadLegacyTemplates()); ManualLogSource logger = <>4__this.logger; if (logger != null) { logger.LogInfo((object)"Delayed initialization complete"); } return false; } IL_007a: if ((Object)(object)ManagerSingleton.Instance == (Object)null && 5__2 < 5__1) { <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } if ((Object)(object)ManagerSingleton.Instance == (Object)null) { ManualLogSource logger2 = <>4__this.logger; if (logger2 != null) { logger2.LogError((object)"IM.Instance failed to initialize within timeout"); } return false; } <>2__current = null; <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__27 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AdvancedChatSosigSpawner <>4__this; private GameObject 5__1; private Exception 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__27(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; try { <>4__this.chatWatcher = Object.FindObjectOfType(); if ((Object)(object)<>4__this.chatWatcher == (Object)null) { 5__1 = new GameObject("H3TVR_ChatWatcher"); <>4__this.chatWatcher = 5__1.AddComponent(); <>4__this.chatWatcher.Initialize(<>4__this.plugin, <>4__this.logger, <>4__this); Object.DontDestroyOnLoad((Object)(object)5__1); <>4__this.chatWatcherEnabled = true; ManualLogSource logger = <>4__this.logger; if (logger != null) { logger.LogInfo((object)"ChatWatcher integration enabled"); } 5__1 = null; } else { <>4__this.chatWatcherEnabled = true; ManualLogSource logger2 = <>4__this.logger; if (logger2 != null) { logger2.LogInfo((object)"ChatWatcher already exists - using existing instance"); } } } catch (Exception ex) { 5__2 = ex; ManualLogSource logger3 = <>4__this.logger; if (logger3 != null) { logger3.LogError((object)("Failed to initialize ChatWatcher: " + 5__2.Message)); } <>4__this.chatWatcherEnabled = false; } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__28 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AdvancedChatSosigSpawner <>4__this; private SteamFriendsIntegration 5__1; private Exception 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__28(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; try { 5__1 = <>4__this.plugin?.GetSteamFriendsIntegration(); if ((Object)(object)5__1 != (Object)null && 5__1.IsAvailable()) { <>4__this.steamFriends = 5__1; ManualLogSource logger = <>4__this.logger; if (logger != null) { logger.LogInfo((object)"Steam Friends integration linked successfully"); } } 5__1 = null; } catch (Exception ex) { 5__2 = ex; ManualLogSource logger2 = <>4__this.logger; if (logger2 != null) { logger2.LogWarning((object)("Failed to link Steam Friends integration: " + 5__2.Message)); } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__30 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AdvancedChatSosigSpawner <>4__this; private SosigEnemyTemplate[] 5__1; private SosigEnemyTemplate[] <>s__2; private int <>s__3; private SosigEnemyTemplate