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 <AirdropSequence>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 <AirdropSequence>d__7 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public AirdropManager <>4__this;
private <>c__DisplayClass7_0 <>8__1;
private Vector3 <spawnPos>5__2;
private FVRObject <crateTemplate>5__3;
private Rigidbody <rb>5__4;
private bool <isHelpful>5__5;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <AirdropSequence>d__7(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>8__1 = null;
<crateTemplate>5__3 = null;
<rb>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;
}
<spawnPos>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;
}
<crateTemplate>5__3 = IM.OD["Crate_Wood_1"];
<>8__1.crateGO = Object.Instantiate<GameObject>(((AnvilAsset)<crateTemplate>5__3).GetGameObject(), <spawnPos>5__2, Quaternion.identity);
<rb>5__4 = <>8__1.crateGO.GetComponent<Rigidbody>();
if ((Object)(object)<rb>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;
}
<rb>5__4.drag = 0.2f;
<isHelpful>5__5 = Random.value < 0.7f;
<>2__current = (object)new WaitUntil((Func<bool>)(() => (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, <isHelpful>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 <AirdropSequence>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<GameObject>(((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>();
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<string> allyNames = new List<string>();
private List<string> enemyNames = new List<string>();
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<string> 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<GameObject>(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>();
Text[] array = componentsInChildren;
foreach (Text val2 in array)
{
val2.text = name;
}
}
}
catch (Exception)
{
}
}
}
public class SosigSpawnConfig
{
public ConfigEntry<int> maxAllySosigs;
public ConfigEntry<int> maxEnemySosigs;
public ConfigEntry<float> spawnCooldown;
public ConfigEntry<bool> enableNameplates;
public ConfigEntry<float> sosigLifetime;
public ConfigEntry<bool> enableAutoCleanup;
public ConfigEntry<float> enemyIFF;
public ConfigEntry<float> followDistance;
public ConfigEntry<float> enemyAggressionDistance;
public ConfigEntry<bool> useModernSpawnSystem;
public ConfigEntry<string> allySosigPool;
public ConfigEntry<string> enemySosigPool;
public ConfigEntry<bool> enableArmorCustomization;
public ConfigEntry<int> maxSosigsPerUser;
public ConfigEntry<bool> enableCoverAI;
public ConfigEntry<float> sosigUpdateInterval;
public ConfigEntry<bool> enableChatWatcherIntegration;
public List<SosigEnemyID> allyPoolIDs = new List<SosigEnemyID>();
public List<SosigEnemyID> enemyPoolIDs = new List<SosigEnemyID>();
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<int>("Chat Spawner", "MaxAllySosigs", 8, "Maximum ally sosigs");
maxEnemySosigs = config.Bind<int>("Chat Spawner", "MaxEnemySosigs", 8, "Maximum enemy sosigs");
spawnCooldown = config.Bind<float>("Chat Spawner", "SpawnCooldown", 2f, "Cooldown between spawns");
enableNameplates = config.Bind<bool>("Chat Spawner", "EnableNameplates", true, "Show nameplates above sosigs");
sosigLifetime = config.Bind<float>("Chat Spawner", "SosigLifetime", 300f, "Sosig lifetime in seconds (0 = infinite)");
enableAutoCleanup = config.Bind<bool>("Chat Spawner", "EnableAutoCleanup", true, "Auto cleanup dead sosigs");
enemyIFF = config.Bind<float>("Chat Spawner", "EnemyIFF", 1f, "Enemy IFF code");
followDistance = config.Bind<float>("Chat Spawner", "FollowDistance", 6f, "Distance for allies to follow player");
enemyAggressionDistance = config.Bind<float>("Chat Spawner", "EnemyAggressionDistance", 20f, "Distance at which enemies become aggressive");
useModernSpawnSystem = config.Bind<bool>("Chat Spawner", "UseModernSpawnSystem", true, "Use Update 120's modern TNH sosig spawn system (recommended)");
allySosigPool = config.Bind<string>("Chat Spawner", "AllySosigPool", "M_Swat_Scout,M_Swat_Sniper,M_Swat_Breacher", "Comma-separated list of SosigEnemyID names for allies");
enemySosigPool = config.Bind<string>("Chat Spawner", "EnemySosigPool", "M_Swat_Heavy,M_Swat_Breacher,M_Swat_Sniper", "Comma-separated list of SosigEnemyID names for enemies");
enableArmorCustomization = config.Bind<bool>("Chat Spawner Advanced", "EnableArmorCustomization", true, "Enable armor customization system");
maxSosigsPerUser = config.Bind<int>("Chat Spawner Advanced", "MaxSosigsPerUser", 2, "Maximum sosigs per Twitch user");
enableCoverAI = config.Bind<bool>("Chat Spawner Advanced", "EnableCoverAI", true, "Enable advanced cover-taking AI behavior");
sosigUpdateInterval = config.Bind<float>("Chat Spawner Advanced", "UpdateInterval", 1f, "Interval between sosig AI updates (seconds)");
enableChatWatcherIntegration = config.Bind<bool>("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>(gameObject, pos, rot);
Sosig componentInChildren = val2.GetComponentInChildren<Sosig>();
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<GameObject>(((AnvilAsset)weaponObj).GetGameObject(), pos + Vector3.up * 0.1f, rot);
SosigWeapon component = val.GetComponent<SosigWeapon>();
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<FVRObject> 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<GameObject>(((AnvilAsset)val).GetGameObject(), ((Component)link).transform.position, ((Component)link).transform.rotation);
val2.transform.SetParent(((Component)link).transform);
SosigWearable component = val2.GetComponent<SosigWearable>();
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<SosigEnemyID, SosigEnemyTemplate> templateCache = new Dictionary<SosigEnemyID, SosigEnemyTemplate>();
private ManualLogSource logger;
public void Initialize(ManualLogSource logSource)
{
logger = logSource;
}
public void BuildCache(List<SosigEnemyID> allyPoolIDs, List<SosigEnemyID> 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<IM>.Instance == (Object)null)
{
ManualLogSource obj = logger;
if (obj != null)
{
obj.LogWarning((object)"Cannot build template cache - IM.Instance is null");
}
return;
}
if (ManagerSingleton<IM>.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<IM>.Instance.odicSosigObjsByID.ContainsKey(item))
{
SosigEnemyTemplate val = ManagerSingleton<IM>.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<IM>.Instance != (Object)null && ManagerSingleton<IM>.Instance.odicSosigObjsByID != null && ManagerSingleton<IM>.Instance.odicSosigObjsByID.ContainsKey(enemyID))
{
SosigEnemyTemplate val = ManagerSingleton<IM>.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>();
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<string> Usernames;
public List<KeyValuePair<string, int>> ArmorCommands;
public List<UserArmorCommand> 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<bool> enableFileWatching;
private ConfigEntry<string> allyChatFilePath;
private ConfigEntry<string> enemyChatFilePath;
private ConfigEntry<float> fileCheckInterval;
private ConfigEntry<bool> clearFileAfterRead;
private float lastFileCheckTime;
private string lastAllyFileContent = "";
private string lastEnemyFileContent = "";
private HashSet<string> processedUsernames = new HashSet<string>();
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<bool>("Chat Watcher - File Mode", "EnableFileWatching", true, "Enable file watching mode for chat integration (H3TwitchTools style)");
allyChatFilePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("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<string>("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<float>("Chat Watcher - File Mode", "FileCheckInterval", 0.5f, "How often to check files for changes (seconds)");
clearFileAfterRead = ((BaseUnityPlugin)plugin).Config.Bind<bool>("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<string, int> 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<string>();
parsedContentResult.ArmorCommands = new List<KeyValuePair<string, int>>();
parsedContentResult.UserArmorCommands = new List<UserArmorCommand>();
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<string, int> 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<string, int> command)
{
command = default(KeyValuePair<string, int>);
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<string, int>(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<string> 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<float> MaxSlomo { get; private set; }
public ConfigEntry<float> SlomoWaitTime { get; private set; }
public ConfigEntry<float> SlomoScaleSpeed { get; private set; }
public ConfigEntry<float> SlomoReturnSpeed { get; private set; }
public ConfigEntry<bool> SlomoVRControllerEnabled { get; private set; }
public ConfigEntry<string> SlomoVRButton { get; private set; }
public ConfigEntry<bool> SlomoAffectsMovement { get; private set; }
public ConfigEntry<float> SlomoMovementScale { get; private set; }
public ConfigEntry<bool> SlomoUseRampSpeed { get; private set; }
public ConfigEntry<string> SlomoRampCurve { get; private set; }
public ConfigEntry<float> SlomoRampDuration { get; private set; }
public ConfigEntry<float> SlomoReturnRampDuration { get; private set; }
public ConfigEntry<bool> EnableKillSlomo { get; private set; }
public ConfigEntry<bool> SlomoAffectsAudio { get; private set; }
public ConfigEntry<float> SlomoAudioPitchScale { get; private set; }
public ConfigEntry<bool> SlomoAudioPreservePitch { get; private set; }
public ConfigEntry<bool> SlomoAffectsAudioSpeed { get; private set; }
public ConfigEntry<float> SlomoAudioSpeedScale { get; private set; }
public ConfigEntry<string> SlomoAudioMode { get; private set; }
public ConfigEntry<bool> UseItemManagerForGunRandomization { get; private set; }
public ConfigEntry<string> GunList { get; private set; }
public ConfigEntry<string> MagazineList { get; private set; }
public ConfigEntry<float> ShurikenScale { get; private set; }
public ConfigEntry<int> ShurikenMinCount { get; private set; }
public ConfigEntry<int> ShurikenMaxCount { get; private set; }
public ConfigEntry<int> PillowMinCount { get; private set; }
public ConfigEntry<int> PillowMaxCount { get; private set; }
public ConfigEntry<bool> PillowGrenadeEnabled { get; private set; }
public ConfigEntry<float> PillowGrenadeChance { get; private set; }
public ConfigEntry<float> PillowGrenadeArmedChance { get; private set; }
public ConfigEntry<bool> PillowZeroGravityEnabled { get; private set; }
public ConfigEntry<float> PillowZeroGravityChance { get; private set; }
public ConfigEntry<float> PillowZeroGravityDuration { get; private set; }
public ConfigEntry<bool> PillowSlomoEnabled { get; private set; }
public ConfigEntry<float> PillowSlomoChance { get; private set; }
public ConfigEntry<float> PillowSlomoDuration { get; private set; }
public ConfigEntry<int> DangerCloseMinCount { get; private set; }
public ConfigEntry<int> DangerCloseMaxCount { get; private set; }
public Dictionary<string, ConfigEntry<KeyCode>> KeyBindings { get; private set; } = new Dictionary<string, ConfigEntry<KeyCode>>();
public ConfigEntry<bool> EnableTwitchChatSosigs { get; private set; }
public ConfigEntry<bool> EnableSteamFriends { get; private set; }
public ConfigEntry<bool> SteamFriendsRandomNames { get; private set; }
public ConfigEntry<float> SteamFriendsRefreshInterval { get; private set; }
public ConfigEntry<bool> EnableInfiniteTokens { get; private set; }
public ConfigEntry<bool> DisableEncryptionNodes { get; private set; }
public ConfigEntry<bool> DisableAllEncryptions { get; private set; }
public ConfigEntry<bool> DisableEncryptionType1 { get; private set; }
public ConfigEntry<bool> DisableEncryptionType2 { get; private set; }
public ConfigEntry<bool> DisableEncryptionType3 { get; private set; }
public ConfigEntry<bool> AutoCompleteEncryption { get; private set; }
public ConfigEntry<float> 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<float>("Slomo", "MaxSlowmoScale", 0.1f, "Maximum slomo scale (0.01 = 1% speed, 0.1 = 10% speed)");
SlomoWaitTime = config.Bind<float>("Slomo", "WaitTime", 2f, "Time to wait at max slomo before returning to normal speed");
SlomoScaleSpeed = config.Bind<float>("Slomo", "ScaleDownSpeed", 1f, "Speed at which time slows down (higher = faster transition)");
SlomoReturnSpeed = config.Bind<float>("Slomo", "ReturnSpeed", 0.33f, "Speed at which time returns to normal (higher = faster return)");
SlomoVRControllerEnabled = config.Bind<bool>("Slomo", "VRControllerEnabled", true, "Enable VR controller button to trigger slomo");
SlomoVRButton = config.Bind<string>("Slomo", "VRButton", "LeftX", "VR button to trigger slomo");
SlomoAffectsMovement = config.Bind<bool>("Slomo", "AffectsMovement", true, "Whether slomo affects player movement speed");
SlomoMovementScale = config.Bind<float>("Slomo", "MovementScale", 0.3f, "Movement speed multiplier during slomo");
SlomoUseRampSpeed = config.Bind<bool>("Slomo.Ramp", "UseRampSpeed", true, "Enable smooth ramp speed transitions for slomo (more cinematic)");
SlomoRampCurve = config.Bind<string>("Slomo.Ramp", "RampCurve", "EaseInOut", "Curve type for slomo ramp: Linear, EaseIn, EaseOut, EaseInOut, Smooth, Cinematic");
SlomoRampDuration = config.Bind<float>("Slomo.Ramp", "RampDuration", 0.5f, "Duration in seconds for slomo to ramp down to max slow speed");
SlomoReturnRampDuration = config.Bind<float>("Slomo.Ramp", "ReturnRampDuration", 0.8f, "Duration in seconds for slomo to ramp back to normal speed");
EnableKillSlomo = config.Bind<bool>("Slomo", "EnableKillSlomo", true, "Enable slow motion effect on enemy kill.");
}
private void InitializeAudioConfig()
{
SlomoAffectsAudio = config.Bind<bool>("Audio", "SlomoAffectsAudio", true, "Whether slomo affects audio pitch");
SlomoAudioPitchScale = config.Bind<float>("Audio", "SlomoAudioPitchScale", 1f, "Audio pitch multiplier during slomo (1.0 = normal pitch, 0.5 = half pitch)");
SlomoAudioPreservePitch = config.Bind<bool>("Audio", "SlomoPreservePitch", false, "If true, audio pitch is preserved (no pitch change). If false, uses pitch scaling.");
SlomoAffectsAudioSpeed = config.Bind<bool>("Audio", "SlomoAffectsAudioSpeed", false, "Whether slomo affects audio speed (time stretching)");
SlomoAudioSpeedScale = config.Bind<float>("Audio", "SlomoAudioSpeedScale", 1f, "Audio speed multiplier during slomo (1.0 = normal speed, 0.5 = half speed)");
SlomoAudioMode = config.Bind<string>("Audio", "SlomoAudioMode", "Both", "Audio adjustment mode during slomo: 'PitchOnly', 'SpeedOnly', 'Both', 'Independent'");
}
private void InitializeGunRandomizationConfig()
{
UseItemManagerForGunRandomization = config.Bind<bool>("GunRandomization", "UseItemManager", true, "Use ItemManager for gun randomization (includes all H3VR and modded guns). If false, uses GunList/MagazineList config files.");
GunList = config.Bind<string>("General", "GunList", "DefaultGunList", "List of guns");
MagazineList = config.Bind<string>("General", "MagazineList", "DefaultMagazineList", "List of magazines");
}
private void InitializeSpawnConfigurations()
{
ShurikenScale = config.Bind<float>("Shuriken", "Scale", 1f, "Scale multiplier for spawned shuriken");
ShurikenMinCount = config.Bind<int>("Shuriken", "MinCount", 1, "Minimum number of shuriken to spawn");
ShurikenMaxCount = config.Bind<int>("Shuriken", "MaxCount", 3, "Maximum number of shuriken to spawn");
PillowMinCount = config.Bind<int>("Pillow", "MinCount", 1, "Minimum number of pillows to spawn");
PillowMaxCount = config.Bind<int>("Pillow", "MaxCount", 3, "Maximum number of pillows to spawn");
PillowGrenadeEnabled = config.Bind<bool>("Pillow", "GrenadeEnabled", true, "Enable pillow grenade effect");
PillowGrenadeChance = config.Bind<float>("Pillow", "GrenadeChance", 0.1f, "Chance for pillow to spawn grenade");
PillowGrenadeArmedChance = config.Bind<float>("Pillow", "GrenadeArmedChance", 0.3f, "Chance for pillow grenade to be armed");
PillowZeroGravityEnabled = config.Bind<bool>("Pillow", "ZeroGEnabled", true, "Enable pillow zero gravity effect");
PillowZeroGravityChance = config.Bind<float>("Pillow", "ZeroGChance", 0.15f, "Chance for pillow to trigger zero gravity");
PillowZeroGravityDuration = config.Bind<float>("Pillow", "ZeroGDuration", 10f, "Duration of pillow zero gravity effect");
PillowSlomoEnabled = config.Bind<bool>("Pillow", "SlomoEnabled", true, "Enable pillow slow motion effect");
PillowSlomoChance = config.Bind<float>("Pillow", "SlomoChance", 0.2f, "Chance for pillow to trigger slow motion");
PillowSlomoDuration = config.Bind<float>("Pillow", "SlomoDuration", 8f, "Duration of pillow slow motion effect");
DangerCloseMinCount = config.Bind<int>("DangerClose", "MinCount", 1, "Minimum danger close rounds");
DangerCloseMaxCount = config.Bind<int>("DangerClose", "MaxCount", 5, "Maximum danger close rounds");
EnableTwitchChatSosigs = config.Bind<bool>("ChatSosigs", "Enabled", true, "Enable Chat Sosig spawning system");
EnableSteamFriends = config.Bind<bool>("SteamFriends", "Enabled", true, "Enable Steam Friends integration for sosig spawning");
SteamFriendsRandomNames = config.Bind<bool>("SteamFriends", "UseRandomNames", false, "Use random friend from list instead of specific name");
SteamFriendsRefreshInterval = config.Bind<float>("SteamFriends", "RefreshInterval", 300f, "Auto-refresh Steam friends list interval (seconds)");
EnableInfiniteTokens = config.Bind<bool>("TakeAndHold", "InfiniteTokens", false, "Enable infinite tokens in Take and Hold mode");
DisableEncryptionNodes = config.Bind<bool>("TakeAndHold", "DisableEncryptionNodes", false, "Disable encryption nodes in Take and Hold mode for easier gameplay");
DisableAllEncryptions = config.Bind<bool>("TakeAndHold.Encryption", "DisableAllEncryptions", false, "Master switch: Disable ALL encryption nodes (overrides specific settings)");
DisableEncryptionType1 = config.Bind<bool>("TakeAndHold.Encryption", "DisableType1", false, "Disable Type 1 encryption nodes (pattern matching)");
DisableEncryptionType2 = config.Bind<bool>("TakeAndHold.Encryption", "DisableType2", false, "Disable Type 2 encryption nodes (sequence)");
DisableEncryptionType3 = config.Bind<bool>("TakeAndHold.Encryption", "DisableType3", false, "Disable Type 3 encryption nodes (timed)");
AutoCompleteEncryption = config.Bind<bool>("TakeAndHold.Encryption", "AutoComplete", false, "Automatically complete enabled encryption nodes after delay");
EncryptionCompletionDelay = config.Bind<float>("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<string, KeyValuePair<KeyCode, string>> dictionary = new Dictionary<string, KeyValuePair<KeyCode, string>>
{
{
"SpawnWonderfulToy",
new KeyValuePair<KeyCode, string>((KeyCode)257, "Spawn Wonderful Toy")
},
{
"SpawnJeditToy",
new KeyValuePair<KeyCode, string>((KeyCode)258, "Spawn Jedit Toy")
},
{
"SpawnHydration",
new KeyValuePair<KeyCode, string>((KeyCode)259, "Spawn Hydration")
},
{
"SpawnPillow",
new KeyValuePair<KeyCode, string>((KeyCode)260, "Spawn Pillow")
},
{
"SpawnShuri",
new KeyValuePair<KeyCode, string>((KeyCode)261, "Spawn Shuriken")
},
{
"SpawnFlash",
new KeyValuePair<KeyCode, string>((KeyCode)262, "Spawn Flash")
},
{
"SpawnFlash2",
new KeyValuePair<KeyCode, string>((KeyCode)263, "Spawn Flash2")
},
{
"SpawnSkittySubGun",
new KeyValuePair<KeyCode, string>((KeyCode)264, "Spawn Random Gun (Small)")
},
{
"SpawnSkittyBigGun",
new KeyValuePair<KeyCode, string>((KeyCode)265, "Spawn Random Gun (Large)")
},
{
"SpawnNadeRain",
new KeyValuePair<KeyCode, string>((KeyCode)267, "Spawn Grenade Rain")
},
{
"DangerCloseBarrage",
new KeyValuePair<KeyCode, string>((KeyCode)268, "Danger Close Barrage")
},
{
"DestroyHeld",
new KeyValuePair<KeyCode, string>((KeyCode)269, "Destroy Held Item")
},
{
"DestroyQuickbelt",
new KeyValuePair<KeyCode, string>((KeyCode)270, "Drop Quickbelt Items")
},
{
"TriggerSlomo",
new KeyValuePair<KeyCode, string>((KeyCode)102, "Trigger Slow Motion")
},
{
"TriggerZeroG",
new KeyValuePair<KeyCode, string>((KeyCode)103, "Trigger Zero Gravity")
},
{
"ToggleFireMode",
new KeyValuePair<KeyCode, string>((KeyCode)116, "Toggle Fire Mode")
},
{
"BoostMalfunction",
new KeyValuePair<KeyCode, string>((KeyCode)121, "Boost Malfunction")
},
{
"ShowStats",
new KeyValuePair<KeyCode, string>((KeyCode)9, "Show Stats")
},
{
"SpawnChatSosigFriendly",
new KeyValuePair<KeyCode, string>((KeyCode)112, "Spawn Friendly Chat Sosig")
},
{
"SpawnChatSosigEnemy",
new KeyValuePair<KeyCode, string>((KeyCode)111, "Spawn Enemy Chat Sosig")
},
{
"CycleChatSosigArmor",
new KeyValuePair<KeyCode, string>((KeyCode)108, "Cycle Chat Sosig Armor")
},
{
"ClearChatSosigs",
new KeyValuePair<KeyCode, string>((KeyCode)127, "Clear All Chat Sosigs")
},
{
"ChatSosigStats",
new KeyValuePair<KeyCode, string>((KeyCode)277, "Show Chat Sosig Stats")
},
{
"SpawnBossWarlord",
new KeyValuePair<KeyCode, string>((KeyCode)98, "Spawn Warlord Boss (Giant)")
},
{
"ClearBosses",
new KeyValuePair<KeyCode, string>((KeyCode)8, "Clear All Bosses")
},
{
"SpawnSteamFriendAlly",
new KeyValuePair<KeyCode, string>((KeyCode)91, "Spawn Steam Friend as Ally")
},
{
"SpawnSteamFriendEnemy",
new KeyValuePair<KeyCode, string>((KeyCode)93, "Spawn Steam Friend as Enemy")
},
{
"SpawnAllSteamFriendsAlly",
new KeyValuePair<KeyCode, string>((KeyCode)288, "Spawn All Steam Friends as Allies")
},
{
"SpawnAllSteamFriendsEnemy",
new KeyValuePair<KeyCode, string>((KeyCode)289, "Spawn All Steam Friends as Enemies")
},
{
"RefreshSteamFriends",
new KeyValuePair<KeyCode, string>((KeyCode)290, "Refresh Steam Friends List")
},
{
"SteamFriendsStats