using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BarberFixes")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fixes some major issues with Barbers")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1+aa71829e449652ff57f84a134f7c9c0c545bdea7")]
[assembly: AssemblyProduct("BarberFixes")]
[assembly: AssemblyTitle("BarberFixes")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BarberFixes
{
[BepInPlugin("butterystancakes.lethalcompany.barberfixes", "Barber Fixes", "1.2.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
private const string PLUGIN_GUID = "butterystancakes.lethalcompany.barberfixes";
private const string PLUGIN_NAME = "Barber Fixes";
private const string PLUGIN_VERSION = "1.2.1";
private const string VENT_SPAWN_FIX = "butterystancakes.lethalcompany.ventspawnfix";
internal static ManualLogSource Logger;
internal static ConfigEntry<bool> configSpawnInPairs;
internal static ConfigEntry<bool> configDrumrollFromAll;
internal static ConfigEntry<bool> configApplySpawningSettings;
internal static ConfigEntry<bool> configOnlyOneBarber;
internal static bool CAN_SPAWN_IN_GROUPS;
private void Awake()
{
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
if (Chainloader.PluginInfos.ContainsKey("butterystancakes.lethalcompany.ventspawnfix"))
{
CAN_SPAWN_IN_GROUPS = true;
Logger.LogInfo((object)"CROSS-COMPATIBILITY - VentSpawnFix detected");
}
configApplySpawningSettings = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "ApplySpawningSettings", false, "The rest of the \"Spawning\" section's settings are only applied if this is enabled. You should disable this if you are using something else to configure enemy variables! (i.e. LethalQuantities)");
configOnlyOneBarber = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "OnlyOneBarber", true, "(Host only) Only allow 1 Barber to spawn each day. Disabling this will raise the limit to 8 per day, as it was before v62.");
configSpawnInPairs = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "SpawnInPairs", false, "(Host only) Spawns Barbers in groups of 2, like in beta v55. This does nothing when \"OnlyOneBarber\" is enabled.\nNOTE: This REQUIRES VentSpawnFix to work!");
configDrumrollFromAll = ((BaseUnityPlugin)this).Config.Bind<bool>("Music", "DrumrollFromAll", false, "If true, all Barbers will play the drumroll audio before they \"jump\". If false, only the master Barber will drumroll.\nThis is false in vanilla, although whether that's by design or a bug is unclear.");
new Harmony("butterystancakes.lethalcompany.barberfixes").PatchAll();
Logger.LogInfo((object)"Barber Fixes v1.2.1 loaded");
}
}
[HarmonyPatch]
internal class BarberFixesPatches
{
private static readonly MethodInfo OBJECT_DESTROY = AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null);
private static readonly FieldInfo MUSIC_AUDIO_2 = AccessTools.Field(typeof(ClaySurgeonAI), "musicAudio2");
private static readonly FieldInfo ON_HOUR_CHANGED = AccessTools.Field(typeof(TimeOfDay), "onHourChanged");
[HarmonyPatch(typeof(ClaySurgeonAI), "ChooseMasterSurgeon")]
[HarmonyPrefix]
private static bool PreChooseMasterSurgeon(ClaySurgeonAI __instance, ref bool ___isMaster)
{
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Expected O, but got Unknown
if (!((NetworkBehaviour)__instance).IsServer)
{
return false;
}
ClaySurgeonAI[] array = Object.FindObjectsOfType<ClaySurgeonAI>();
if (array.Length == 1)
{
__instance.master = __instance;
}
else
{
__instance.master = ((IEnumerable<ClaySurgeonAI>)array).FirstOrDefault((Func<ClaySurgeonAI, bool>)((ClaySurgeonAI barber) => (Object)(object)barber.master == (Object)(object)barber));
if ((Object)(object)__instance.master == (Object)null)
{
__instance.master = __instance;
}
}
if ((Object)(object)__instance.master == (Object)(object)__instance)
{
___isMaster = true;
DanceClock.Start(__instance.startingInterval, __instance.endingInterval);
}
__instance.master.SendDanceBeat = new SimpleEvent();
for (int i = 0; i < array.Length; i++)
{
if (!__instance.master.allClaySurgeons.Contains(array[i]))
{
__instance.master.allClaySurgeons.Add(array[i]);
}
if ((Object)(object)array[i] != (Object)(object)__instance.master)
{
array[i].master = __instance.master;
array[i].ListenToMasterSurgeon();
}
}
__instance.master.SyncMasterClaySurgeonClientRpc();
return false;
}
[HarmonyPatch(typeof(ClaySurgeonAI), "ListenToMasterSurgeon")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> TransListenToMasterSurgeon(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = instructions.ToList();
Label? label = null;
for (int i = 0; i < list.Count; i++)
{
if (!label.HasValue)
{
if (list[i].opcode == OpCodes.Brtrue)
{
label = (Label)list[i].operand;
Plugin.Logger.LogDebug((object)"Transpiler (ListenToMasterSurgeon): Allow when \"listeningToMasterSurgeon\" is already true");
}
list.RemoveAt(i--);
continue;
}
if (list[i].opcode == OpCodes.Call && (MethodInfo)list[i].operand == OBJECT_DESTROY && list[i - 2].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 2].operand == MUSIC_AUDIO_2)
{
list.RemoveRange(i - 3, 4);
Plugin.Logger.LogDebug((object)"Transpiler (ListenToMasterSurgeon): Don't destroy \"musicAudio2\" (causes NRE)");
i -= 3;
}
if (list[i].labels.Contains(label.Value))
{
list[i].labels.Remove(label.Value);
}
}
return list;
}
[HarmonyPatch(typeof(ClaySurgeonAI), "SyncMasterClaySurgeonClientRpc")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> TransSyncMasterClaySurgeonClientRpc(IEnumerable<CodeInstruction> instructions)
{
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Expected O, but got Unknown
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Expected O, but got Unknown
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Expected O, but got Unknown
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Expected O, but got Unknown
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Expected O, but got Unknown
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Callvirt && list[i].operand.ToString().Contains("AddListener") && list[i - 4].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 4].operand == ON_HOUR_CHANGED)
{
list.RemoveRange(i - 5, 6);
Plugin.Logger.LogDebug((object)"Transpiler (SyncMasterClaySurgeonClientRpc): Don't add listener to \"onHourChanged\"");
i -= 5;
list.InsertRange(i, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[5]
{
new CodeInstruction(OpCodes.Ldarg_0, (object)null),
new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(ClaySurgeonAI), "startingInterval")),
new CodeInstruction(OpCodes.Ldarg_0, (object)null),
new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(ClaySurgeonAI), "endingInterval")),
new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DanceClock), "Start", (Type[])null, (Type[])null))
}));
Plugin.Logger.LogDebug((object)"Transpiler (SyncMasterClaySurgeonClientRpc): Use new \"DanceClock\"");
}
else if (list[i].opcode == OpCodes.Call && (MethodInfo)list[i].operand == OBJECT_DESTROY && list[i - 2].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 2].operand == MUSIC_AUDIO_2)
{
list.RemoveRange(i - 6, 7);
Plugin.Logger.LogDebug((object)"Transpiler (SyncMasterClaySurgeonClientRpc): Don't destroy \"musicAudio2\" (causes NRE)");
i -= 6;
}
}
return list;
}
[HarmonyPatch(typeof(ClaySurgeonAI), "OnDestroy")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> ClaySurgeonAITransOnDestroy(IEnumerable<CodeInstruction> instructions)
{
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Expected O, but got Unknown
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Callvirt && list[i].operand.ToString().Contains("RemoveListener") && list[i - 4].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 4].operand == ON_HOUR_CHANGED)
{
list.RemoveRange(i - 5, 6);
Plugin.Logger.LogDebug((object)"Transpiler (ClaySurgeonAI.OnDestroy): Don't remove listener from \"onHourChanged\"");
i -= 5;
list.Insert(i, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DanceClock), "Stop", (Type[])null, (Type[])null)));
Plugin.Logger.LogDebug((object)"Transpiler (ClaySurgeonAI.OnDestroy): Use new \"DanceClock\"");
}
}
return list;
}
[HarmonyPatch(typeof(ClaySurgeonAI), "KillPlayerClientRpc")]
[HarmonyPostfix]
private static void ClaySurgeonAIPostKillPlayerClientRpc(ClaySurgeonAI __instance, ref bool ___isMaster, ref float ___beatTimer, ref float ___snareIntervalTimer)
{
if (((NetworkBehaviour)__instance).IsOwner & ___isMaster)
{
___beatTimer = Mathf.Min(___beatTimer, 4f + __instance.snareOffset);
___snareIntervalTimer = ___beatTimer - __instance.snareOffset;
}
}
[HarmonyPatch(typeof(ClaySurgeonAI), "PlayMusic")]
[HarmonyPostfix]
private static void ClaySurgeonAIPostPlayMusic(ClaySurgeonAI __instance, float ___snareIntervalTimer)
{
if (___snareIntervalTimer != 100f || !Plugin.configDrumrollFromAll.Value)
{
return;
}
foreach (ClaySurgeonAI allClaySurgeon in __instance.allClaySurgeons)
{
if ((Object)(object)allClaySurgeon != (Object)(object)__instance)
{
allClaySurgeon.musicAudio.PlayOneShot(allClaySurgeon.snareDrum);
WalkieTalkie.TransmitOneShotAudio(allClaySurgeon.musicAudio, allClaySurgeon.snareDrum, 1f);
}
}
}
[HarmonyPatch(typeof(RoundManager), "PlotOutEnemiesForNextHour")]
[HarmonyPrefix]
private static void PrePlotOutEnemiesForNextHour(RoundManager __instance)
{
if (!((NetworkBehaviour)__instance).IsServer || !Plugin.configApplySpawningSettings.Value)
{
return;
}
int num = 1;
if (Plugin.configSpawnInPairs.Value)
{
if (Plugin.CAN_SPAWN_IN_GROUPS)
{
if (Plugin.configOnlyOneBarber.Value)
{
Plugin.Logger.LogWarning((object)"Config setting \"SpawnInPairs\" has been enabled, but will be ignored as \"OnlyOneBarber\" is also enabled.");
}
else
{
num = 2;
}
}
else
{
Plugin.Logger.LogWarning((object)"Config setting \"SpawnInPairs\" has been enabled, but VentSpawnFix was not detected. Enemies spawning from vents in groups is unsupported by vanilla, so this setting won't work!");
}
}
EnemyType val = ((IEnumerable<SpawnableEnemyWithRarity>)__instance.currentLevel.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)delegate(SpawnableEnemyWithRarity enemy)
{
EnemyType enemyType = enemy.enemyType;
return ((enemyType != null) ? ((Object)enemyType).name : null) == "ClaySurgeon";
})?.enemyType;
if ((Object)(object)val != (Object)null)
{
if (val.spawnInGroupsOf != num)
{
Plugin.Logger.LogDebug((object)$"ClaySurgeon.spawnInGroupsOf: {val.spawnInGroupsOf} -> {num}");
val.spawnInGroupsOf = num;
}
int num2 = (Plugin.configOnlyOneBarber.Value ? 1 : 8);
if (val.MaxCount != num2)
{
Plugin.Logger.LogDebug((object)$"ClaySurgeon.MaxCount: {val.MaxCount} -> {num2}");
val.MaxCount = num2;
}
}
}
[HarmonyPatch(typeof(ClaySurgeonAI), "Start")]
[HarmonyPostfix]
private static void ClaySurgeonAIPostStart(ClaySurgeonAI __instance, ref float ___snareIntervalTimer)
{
((EnemyAI)__instance).agent.speed = 0f;
___snareIntervalTimer = 100f;
EnemyAICollisionDetect componentInChildren = ((Component)__instance).GetComponentInChildren<EnemyAICollisionDetect>();
GameObject val = ((componentInChildren != null) ? ((Component)componentInChildren).gameObject : null);
if ((Object)(object)val != (Object)null && !Object.op_Implicit((Object)(object)val.GetComponent<Rigidbody>()))
{
Rigidbody obj = val.AddComponent<Rigidbody>();
obj.isKinematic = true;
obj.collisionDetectionMode = (CollisionDetectionMode)3;
}
}
[HarmonyPatch(typeof(ClaySurgeonAI), "OnCollideWithPlayer")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> ClaySurgeonAITransOnCollideWithPlayer(IEnumerable<CodeInstruction> instructions)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Expected O, but got Unknown
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Expected O, but got Unknown
List<CodeInstruction> list = instructions.ToList();
list.InsertRange(list.Count - 1, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[3]
{
new CodeInstruction(OpCodes.Ldarg_0, (object)null),
new CodeInstruction(OpCodes.Ldc_R4, (object)0f),
new CodeInstruction(OpCodes.Stfld, (object)AccessTools.Field(typeof(ClaySurgeonAI), "timeSinceSnip"))
}));
Plugin.Logger.LogDebug((object)"Transpiler (ClaySurgeonAI.OnCollideWithPlayer): Set cooldown for local client immediately");
return list;
}
}
public class DanceClock
{
[CompilerGenerated]
private static class <>O
{
public static UnityAction <0>__Tick;
}
private static bool ticking;
private static float startingInterval = 2.75f;
private static float endingInterval = 1.25f;
internal static void Start(float start, float end)
{
//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_003f: Expected O, but got Unknown
if (!ticking)
{
ticking = true;
startingInterval = start;
endingInterval = end;
UnityEvent onHourChanged = TimeOfDay.Instance.onHourChanged;
object obj = <>O.<0>__Tick;
if (obj == null)
{
UnityAction val = Tick;
<>O.<0>__Tick = val;
obj = (object)val;
}
onHourChanged.AddListener((UnityAction)obj);
}
}
public static void Tick()
{
float currentInterval = Mathf.Lerp(startingInterval, endingInterval, (float)TimeOfDay.Instance.hour / (float)TimeOfDay.Instance.numberOfHours);
ClaySurgeonAI[] array = Object.FindObjectsOfType<ClaySurgeonAI>();
for (int i = 0; i < array.Length; i++)
{
array[i].currentInterval = currentInterval;
}
}
internal static void Stop()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
if (ticking)
{
ticking = false;
UnityEvent onHourChanged = TimeOfDay.Instance.onHourChanged;
object obj = <>O.<0>__Tick;
if (obj == null)
{
UnityAction val = Tick;
<>O.<0>__Tick = val;
obj = (object)val;
}
onHourChanged.RemoveListener((UnityAction)obj);
}
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "BarberFixes";
public const string PLUGIN_NAME = "BarberFixes";
public const string PLUGIN_VERSION = "1.2.1";
}
}
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
int ICollection.Count => _items.Length;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
object IList.this[int index]
{
get
{
return _items[index];
}
set
{
throw new NotSupportedException();
}
}
bool IList.IsFixedSize => true;
bool IList.IsReadOnly => true;
int IReadOnlyCollection<T>.Count => _items.Length;
T IReadOnlyList<T>.this[int index] => _items[index];
int ICollection<T>.Count => _items.Length;
bool ICollection<T>.IsReadOnly => true;
T IList<T>.this[int index]
{
get
{
return _items[index];
}
set
{
throw new NotSupportedException();
}
}
public <>z__ReadOnlyArray(T[] items)
{
_items = items;
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_items).GetEnumerator();
}
void ICollection.CopyTo(Array array, int index)
{
((ICollection)_items).CopyTo(array, index);
}
int IList.Add(object value)
{
throw new NotSupportedException();
}
void IList.Clear()
{
throw new NotSupportedException();
}
bool IList.Contains(object value)
{
return ((IList)_items).Contains(value);
}
int IList.IndexOf(object value)
{
return ((IList)_items).IndexOf(value);
}
void IList.Insert(int index, object value)
{
throw new NotSupportedException();
}
void IList.Remove(object value)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)_items).GetEnumerator();
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Contains(T item)
{
return ((ICollection<T>)_items).Contains(item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
((ICollection<T>)_items).CopyTo(array, arrayIndex);
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
int IList<T>.IndexOf(T item)
{
return ((IList<T>)_items).IndexOf(item);
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
}