using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LCFairCompany.Configs;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("LCFairCompany")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Mod to tweak some monsters in Lethal Company to make them more balanced, now fully configurable and synced with the Host!")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: AssemblyInformationalVersion("2.1.0+a6432e10395b947dccd01f14c65e0154edf3f185")]
[assembly: AssemblyProduct("LCFairCompany")]
[assembly: AssemblyTitle("LCFairCompany")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.0.0")]
[module: UnverifiableCode]
namespace LCFairCompany
{
[StructLayout(LayoutKind.Sequential, Size = 1)]
internal struct EntitiesName
{
public const string SnareFlea = "Centipede";
public const string BunkerSpider = "Bunker Spider";
public const string HoardingBug = "Hoarding Bug";
public const string Bracken = "Flowerman";
public const string Thumper = "Crawler";
public const string Hydrogene = "Blob";
public const string GhostGirl = "Girl";
public const string SporeLizard = "Puffer";
public const string Nutcracker = "Nutcracker";
public const string Coilhead = "Spring";
public const string Jester = "Jester";
public const string Masked = "Masked";
public const string EyelessDog = "MouthDog";
public const string ForestKeeper = "ForestGiant";
public const string EarthLeviathan = "Earth Leviathan";
public const string BaboonHawk = "Baboon hawk";
public const string CircuitBees = "Red Locust Bees";
public const string Manticoil = "Manticoil";
public const string RoamingLocusts = "Docile Locust Bees";
public const string LassoMan = "Lasso";
}
internal static class EnemyHelpers
{
public static bool IsMatchingName(this EnemyType enemyType, string enemyName)
{
return enemyType.enemyName.Equals(enemyName, StringComparison.OrdinalIgnoreCase);
}
public static void SetEnemyPowerLevel(this EnemyType enemyType, float powerLevel)
{
if (Mathf.Approximately(enemyType.PowerLevel, powerLevel))
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)$"\"{enemyType.enemyName}\" PowerLevel is already {powerLevel}, nothing to change");
}
return;
}
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogInfo((object)$"Changing \"{enemyType.enemyName}\" PowerLevel ({enemyType.PowerLevel} => {powerLevel})");
}
enemyType.PowerLevel = powerLevel;
}
public static void SetEnemyMaxCount(this EnemyType enemyType, int maxCount)
{
if (enemyType.MaxCount == maxCount)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)$"\"{enemyType.enemyName}\" MaxCount is already {maxCount}, nothing to change");
}
return;
}
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogInfo((object)$"Changing \"{enemyType.enemyName}\" MaxCount ({enemyType.MaxCount} => {maxCount})");
}
enemyType.MaxCount = maxCount;
}
public static void SetEnemyHP(this EnemyAI enemyAI, int enemyHP)
{
if (enemyAI.enemyHP == enemyHP)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)$"\"{enemyAI.enemyType.enemyName}\" EnemyHP is already {enemyHP}, nothing to change");
}
return;
}
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogInfo((object)$"Changing \"{enemyAI.enemyType.enemyName}\" EnemyHP ({enemyAI.enemyHP} => {enemyHP})");
}
enemyAI.enemyHP = enemyHP;
}
}
internal static class AudioHelpers
{
public static int PlayRandomOneShot(this AudioSource audioSource, AudioClip[] clipsArray, float volume = 1f, float? minDistance = null, float? maxDistance = null, bool bTransmitToWalkieTalkie = true, int timesPlayedInSameSpot = 0)
{
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)audioSource == (Object)null || clipsArray == null || clipsArray.Length == 0)
{
return -1;
}
float pitch = audioSource.pitch;
float minDistance2 = audioSource.minDistance;
float maxDistance2 = audioSource.maxDistance;
audioSource.pitch = Random.Range(0.94f, 1.06f);
if (minDistance.HasValue)
{
audioSource.minDistance = minDistance.Value;
}
if (maxDistance.HasValue)
{
audioSource.maxDistance = maxDistance.Value;
}
int num = Random.Range(0, clipsArray.Length);
audioSource.PlayOneShot(clipsArray[num], volume);
if (bTransmitToWalkieTalkie)
{
WalkieTalkie.TransmitOneShotAudio(audioSource, clipsArray[num], 0.85f * volume);
}
if (audioSource.spatialBlend > 0f)
{
RoundManager.Instance.PlayAudibleNoise(((Component)audioSource).transform.position, 4f * volume, volume / 2f, timesPlayedInSameSpot, false, 0);
}
audioSource.pitch = pitch;
audioSource.minDistance = minDistance2;
audioSource.maxDistance = maxDistance2;
return num;
}
}
[BepInPlugin("LCFairCompany", "LCFairCompany", "2.1.0")]
internal class Plugin : BaseUnityPlugin
{
private readonly Harmony _harmony = null;
private readonly ConfigManager _configManager = null;
internal static ManualLogSource Logger { get; private set; }
protected Plugin()
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
_harmony = new Harmony("LCFairCompany");
_configManager = new ConfigManager(((BaseUnityPlugin)this).Config);
}
protected void Awake()
{
ManualLogSource logger = Logger;
if (logger != null)
{
logger.LogInfo((object)"Plugin LCFairCompany is loaded!");
}
ManualLogSource logger2 = Logger;
if (logger2 != null)
{
logger2.LogDebug((object)"Patching harmony...");
}
_harmony.PatchAll(Assembly.GetExecutingAssembly());
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "LCFairCompany";
public const string PLUGIN_NAME = "LCFairCompany";
public const string PLUGIN_VERSION = "2.1.0";
}
}
namespace LCFairCompany.Patches
{
[HarmonyPatch(typeof(CentipedeAI))]
internal class CentipedeAIPatch : MonoBehaviour
{
private CentipedeAI _centipedeAI = null;
private int _damageSinceClingingToPlayer = 0;
private int _timesPlayedInSameSpot = 0;
private float? _delayUntilNextAudioCue = null;
private bool LimitDamagePerClinging => SyncedInstance<ConfigManager>.Instance.Centipede.LimitDamagePerClinging.Value;
private int MaxDamagePerClinging => SyncedInstance<ConfigManager>.Instance.Centipede.MaxDamagePerClinging.Value;
private bool PlayAudioShriekOnCeiling => SyncedInstance<ConfigManager>.Default.Centipede.PlayAudioShriekOnCeiling.Value;
private int AudioShriekMinFrequency => SyncedInstance<ConfigManager>.Default.Centipede.AudioShriekMinFrequency.Value;
private int AudioShriekMaxFrequency => SyncedInstance<ConfigManager>.Default.Centipede.AudioShriekMaxFrequency.Value;
protected void Start()
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)"\"Centipede\" applies \"CentipedeAIPatch\"");
}
_centipedeAI = ((Component)this).gameObject.GetComponent<CentipedeAI>();
}
protected void LateUpdate()
{
if (PlayAudioShriekOnCeiling)
{
UpdateDelayUntilNextAudioCue(Time.deltaTime);
}
else
{
_delayUntilNextAudioCue = null;
}
}
public void OnPlayerDamaged(int damage)
{
if (_centipedeAI.inDroppingOffPlayerAnim)
{
return;
}
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)string.Format("Updating \"{0}\" DamageSinceClingingToPlayer ({1} => {2})", "Centipede", _damageSinceClingingToPlayer, _damageSinceClingingToPlayer + damage));
}
_damageSinceClingingToPlayer += damage;
bool flag = false;
if (StartOfRound.Instance.connectedPlayersAmount > 0 && StartOfRound.Instance.livingPlayers == 1 && _centipedeAI.clingingToPlayer.health <= 15 && !StartOfRoundPatch.LastSurvivorSecondChanceGiven)
{
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogInfo((object)"\"Centipede\" is attempting to kill the last survivor");
}
StartOfRoundPatch.LastSurvivorSecondChanceGiven = true;
flag = true;
}
else if (LimitDamagePerClinging && _damageSinceClingingToPlayer >= MaxDamagePerClinging)
{
ManualLogSource logger3 = Plugin.Logger;
if (logger3 != null)
{
logger3.LogInfo((object)string.Format("\"{0}\" reached MaxDamagePerClinging ({1}/{2})", "Centipede", _damageSinceClingingToPlayer, MaxDamagePerClinging));
}
flag = true;
}
if (flag)
{
_centipedeAI.inDroppingOffPlayerAnim = true;
_centipedeAI.StopClingingServerRpc(false);
}
}
public void OnStopClingingToPlayer()
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)string.Format("Resetting \"{0}\" DamageSinceClingingToPlayer ({1} => 0)", "Centipede", _damageSinceClingingToPlayer));
}
_damageSinceClingingToPlayer = 0;
}
private void PlayRandomShriekSFX()
{
if (!((Object)(object)_centipedeAI == (Object)null))
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)string.Format("Playing \"{0}\" RandomShriekSFX ({1}={2})", "Centipede", "_timesPlayedInSameSpot", _timesPlayedInSameSpot));
}
((EnemyAI)_centipedeAI).creatureSFX.PlayRandomOneShot(_centipedeAI.shriekClips, 0.1f, 10f, 35f, bTransmitToWalkieTalkie: false, _timesPlayedInSameSpot);
}
}
private void UpdateDelayUntilNextAudioCue(float deltaTime)
{
if ((Object)(object)_centipedeAI == (Object)null || !((NetworkBehaviour)_centipedeAI).IsClient || !_centipedeAI.clingingToCeiling || _centipedeAI.ceilingAnimationCoroutine != null)
{
_delayUntilNextAudioCue = null;
_timesPlayedInSameSpot = 0;
return;
}
if (!_delayUntilNextAudioCue.HasValue)
{
float num = 60f / (float)Mathf.Max(AudioShriekMaxFrequency, 1);
float num2 = 60f / (float)Mathf.Max(AudioShriekMinFrequency, 1);
if (num <= num2)
{
_delayUntilNextAudioCue = Random.Range(num, num2);
}
else
{
_delayUntilNextAudioCue = Random.Range(num2, num);
}
}
_delayUntilNextAudioCue -= deltaTime;
if (_delayUntilNextAudioCue <= 0f)
{
PlayRandomShriekSFX();
_delayUntilNextAudioCue = null;
_timesPlayedInSameSpot++;
}
}
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void StartPostfix(CentipedeAI __instance)
{
((Component)__instance).gameObject.AddComponent<CentipedeAIPatch>();
}
[HarmonyPatch("DamagePlayerOnIntervals")]
[HarmonyPrefix]
private static void DamagePlayerOnIntervalsPrefix(CentipedeAI __instance, out int __state)
{
__state = __instance.clingingToPlayer?.health ?? 0;
}
[HarmonyPatch("DamagePlayerOnIntervals")]
[HarmonyPostfix]
private static void DamagePlayerOnIntervalsPostfix(CentipedeAI __instance, int __state)
{
int valueOrDefault = (__state - __instance.clingingToPlayer?.health).GetValueOrDefault();
CentipedeAIPatch centipedeAIPatch = default(CentipedeAIPatch);
if (valueOrDefault > 0 && ((Component)__instance).gameObject.TryGetComponent<CentipedeAIPatch>(ref centipedeAIPatch))
{
centipedeAIPatch.OnPlayerDamaged(valueOrDefault);
}
}
[HarmonyPatch("ClingToPlayer")]
[HarmonyPostfix]
private static void ClingToPlayerPostfix(CentipedeAI __instance, PlayerControllerB playerScript)
{
PlayerControllerBPatch playerControllerBPatch = default(PlayerControllerBPatch);
if (((Component)playerScript).TryGetComponent<PlayerControllerBPatch>(ref playerControllerBPatch))
{
playerControllerBPatch.OnClingToPlayer(__instance);
}
}
[HarmonyPatch("StopClingingToPlayer")]
[HarmonyPrefix]
private static void StopClingingToPlayerPrefix(CentipedeAI __instance)
{
PlayerControllerBPatch playerControllerBPatch = default(PlayerControllerBPatch);
if (((Component)__instance.clingingToPlayer).TryGetComponent<PlayerControllerBPatch>(ref playerControllerBPatch))
{
playerControllerBPatch.OnStopClingingToPlayer();
}
}
[HarmonyPatch("StopClingingToPlayer")]
[HarmonyPostfix]
private static void StopClingingToPlayerPostfix(CentipedeAI __instance)
{
CentipedeAIPatch centipedeAIPatch = default(CentipedeAIPatch);
if (((Component)__instance).gameObject.TryGetComponent<CentipedeAIPatch>(ref centipedeAIPatch))
{
centipedeAIPatch.OnStopClingingToPlayer();
}
}
}
[HarmonyPatch(typeof(EnemyAI))]
internal static class EnemyAIPatch
{
[HarmonyPatch("PlayerIsTargetable")]
[HarmonyPostfix]
private static void PlayerIsTargetablePostfix(ref bool __result, EnemyAI __instance, PlayerControllerB playerScript)
{
PlayerControllerBPatch playerControllerBPatch = default(PlayerControllerBPatch);
if (__result && __instance is CentipedeAI && ((Component)playerScript).TryGetComponent<PlayerControllerBPatch>(ref playerControllerBPatch) && playerControllerBPatch.IsClingingToPlayer())
{
__result = false;
}
}
}
[HarmonyPatch(typeof(GameNetworkManager))]
internal class GameNetworkManagerPatch
{
[HarmonyPatch("SteamMatchmaking_OnLobbyMemberJoined")]
[HarmonyPostfix]
private static void SteamMatchmaking_OnLobbyMemberJoinedPostfix()
{
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
if (SyncedInstance<ConfigManager>.IsHost)
{
SyncedInstance<ConfigManager>.MessageManager.RegisterNamedMessageHandler("LCFairCompany_OnRequestConfigSync", new HandleNamedMessageDelegate(ConfigManager.OnRequestSync));
SyncedInstance<ConfigManager>.Synced = true;
}
else
{
SyncedInstance<ConfigManager>.Synced = false;
SyncedInstance<ConfigManager>.MessageManager.RegisterNamedMessageHandler("LCFairCompany_OnReceiveConfigSync", new HandleNamedMessageDelegate(ConfigManager.OnReceiveSync));
ConfigManager.RequestSync();
}
}
[HarmonyPatch("StartDisconnect")]
[HarmonyPostfix]
public static void StartDisconnectPostfix()
{
SyncedInstance<ConfigManager>.RevertSync();
}
}
[HarmonyPatch(typeof(PlayerControllerB))]
internal class PlayerControllerBPatch : MonoBehaviour
{
private PlayerControllerB _playerController = null;
private CentipedeAI _clingingToPlayer = null;
protected void Start()
{
_playerController = ((Component)this).gameObject.GetComponent<PlayerControllerB>();
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)("\"" + _playerController.playerUsername + "\" applies \"PlayerControllerBPatch\""));
}
}
public void OnClingToPlayer(CentipedeAI centipedeAI)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)("\"Centipede\" has latched on player \"" + _playerController?.playerUsername + "\""));
}
_clingingToPlayer = centipedeAI;
}
public void OnStopClingingToPlayer()
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)("\"Centipede\" has dropped from player \"" + _playerController?.playerUsername + "\""));
}
_clingingToPlayer = null;
}
public bool IsClingingToPlayer()
{
return (Object)(object)_clingingToPlayer != (Object)null && !((EnemyAI)_clingingToPlayer).isEnemyDead;
}
[HarmonyPatch("Awake")]
[HarmonyPostfix]
private static void PlayerControllerBAwakePostfix(PlayerControllerB __instance)
{
((Component)__instance).gameObject.AddComponent<PlayerControllerBPatch>();
}
}
[HarmonyPatch(typeof(SandSpiderAI))]
internal static class SandSpiderAIPatch
{
private static int Health => SyncedInstance<ConfigManager>.Instance.Spider.Health.Value;
private static int Damage => SyncedInstance<ConfigManager>.Instance.Spider.Damage.Value;
private static int ScaleDPS => SyncedInstance<ConfigManager>.Instance.Spider.ScaleDPS.Value;
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void StartPostfix(SandSpiderAI __instance)
{
((EnemyAI)(object)__instance).SetEnemyHP(Health);
}
[HarmonyPatch("OnCollideWithPlayer")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> OnCollideWithPlayerTranspiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = instructions.ToList();
bool flag = false;
float num = (float)Damage / 1f;
float num2 = num * (float)ScaleDPS / 100f;
float num3 = (float)Damage / num2;
FieldInfo fieldInfo = AccessTools.Field(typeof(SandSpiderAI), "timeSinceHittingPlayer");
bool flag2 = false;
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)string.Format("Enumerating code instructions in \"{0}\" until we find the hardcoded damage ({1}) and cooldown ({2})...", "OnCollideWithPlayer", 90, 1f));
}
for (int i = 0; i < list.Count; i++)
{
if (CodeInstructionExtensions.LoadsConstant(list[i], 90L))
{
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogInfo((object)string.Format("Changing \"{0}\" Damage ({1} => {2})", "Bunker Spider", 90, Damage));
}
list[i].operand = Damage;
flag = true;
}
if (CodeInstructionExtensions.LoadsField(list[i], fieldInfo, false) && i + 1 < list.Count && CodeInstructionExtensions.LoadsConstant(list[i + 1], 1.0))
{
ManualLogSource logger3 = Plugin.Logger;
if (logger3 != null)
{
logger3.LogInfo((object)string.Format("Changing \"{0}\" HitCooldown ({1} => {2})", "Bunker Spider", 1f, num3));
}
list[i + 1].operand = num3;
flag2 = true;
}
if (flag && flag2)
{
break;
}
}
if (!flag)
{
ManualLogSource logger4 = Plugin.Logger;
if (logger4 != null)
{
logger4.LogError((object)string.Format("[{0}] Cannot find hardcoded damage ({1})", "OnCollideWithPlayer", 90));
}
}
if (!flag2)
{
ManualLogSource logger5 = Plugin.Logger;
if (logger5 != null)
{
logger5.LogError((object)string.Format("[{0}] Cannot find \"{1}\" or hardcoded cooldown ({2})", "OnCollideWithPlayer", fieldInfo.Name, 1f));
}
}
return list;
}
}
[HarmonyPatch(typeof(StartOfRound))]
internal static class StartOfRoundPatch
{
public static bool LastSurvivorSecondChanceGiven;
private static bool BunkerSpiderChangeMaxCount => SyncedInstance<ConfigManager>.Instance.Enemy.BunkerSpiderChangeMaxCount.Value;
private static bool CoilheadChangePowerLevel => SyncedInstance<ConfigManager>.Instance.Enemy.CoilheadChangePowerLevel.Value;
private static bool CoilheadChangeMaxCount => SyncedInstance<ConfigManager>.Instance.Enemy.CoilheadChangeMaxCount.Value;
private static bool GhostGirlChangePowerLevel => SyncedInstance<ConfigManager>.Instance.Enemy.GhostGirlChangePowerLevel.Value;
private static bool JesterChangePowerLevel => SyncedInstance<ConfigManager>.Instance.Enemy.JesterChangePowerLevel.Value;
[HarmonyPatch("StartGame")]
[HarmonyPostfix]
private static void StartGamePostfix()
{
LastSurvivorSecondChanceGiven = false;
if (StartOfRound.Instance == null || !((NetworkBehaviour)StartOfRound.Instance).IsServer)
{
return;
}
if (StartOfRound.Instance.currentLevel == null)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogError((object)"currentLevel is null!");
}
return;
}
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogDebug((object)"Enumerating all spawnable enemies...");
}
foreach (SpawnableEnemyWithRarity enemy in StartOfRound.Instance.currentLevel.Enemies)
{
if (enemy == null || enemy.enemyType == null)
{
continue;
}
EnemyType enemyType = enemy.enemyType;
ManualLogSource logger3 = Plugin.Logger;
if (logger3 != null)
{
logger3.LogDebug((object)("Found spawnable enemy: \"" + enemyType.enemyName + "\""));
}
if (enemyType.IsMatchingName("Bunker Spider"))
{
if (BunkerSpiderChangeMaxCount)
{
enemyType.SetEnemyMaxCount(2);
}
}
else if (enemyType.IsMatchingName("Spring"))
{
if (CoilheadChangePowerLevel)
{
enemyType.SetEnemyPowerLevel(1.5f);
}
if (CoilheadChangeMaxCount)
{
enemyType.SetEnemyMaxCount(4);
}
}
else if (enemyType.IsMatchingName("Girl"))
{
if (GhostGirlChangePowerLevel)
{
enemyType.SetEnemyPowerLevel(3f);
}
}
else if (enemyType.IsMatchingName("Jester") && JesterChangePowerLevel)
{
enemyType.SetEnemyPowerLevel(2f);
}
}
}
}
}
namespace LCFairCompany.Configs
{
internal class CentipedeConfig
{
public ConfigEntry<bool> LimitDamagePerClinging { get; private set; } = null;
public ConfigEntry<int> MaxDamagePerClinging { get; private set; } = null;
public ConfigEntry<bool> PlayAudioShriekOnCeiling { get; private set; } = null;
public ConfigEntry<int> AudioShriekMinFrequency { get; private set; } = null;
public ConfigEntry<int> AudioShriekMaxFrequency { get; private set; } = null;
public CentipedeConfig(ConfigFile config)
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Expected O, but got Unknown
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Expected O, but got Unknown
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Expected O, but got Unknown
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Expected O, but got Unknown
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Expected O, but got Unknown
if (config == null)
{
throw new ArgumentNullException("config");
}
LimitDamagePerClinging = config.Bind<bool>("Snare Flea Settings", "Limit Damage Per Clinging", true, new ConfigDescription("Limit how much damage Snare Fleas can inflict per clinging to any player (i.e. prevents getting oneshot if a player doesn't find a shovel or the exit in time).", (AcceptableValueBase)null, Array.Empty<object>()));
MaxDamagePerClinging = config.Bind<int>("Snare Flea Settings", "Max Damage Per Clinging", 60, new ConfigDescription("If limit is applied, Snare Fleas stop clinging from any player after inflicting that much damage.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 100), Array.Empty<object>()));
PlayAudioShriekOnCeiling = config.Bind<bool>("Snare Flea Settings (client only)", "Play Audio Shriek On Ceiling", true, new ConfigDescription("Add a quiet audio shriek (triggering 3 to 4 times per minute by default) when a Snare Flea is on a ceiling.", (AcceptableValueBase)null, Array.Empty<object>()));
AudioShriekMinFrequency = config.Bind<int>("Snare Flea Settings (client only)", "Audio Shriek Min Frequency", 3, new ConfigDescription("Snare Fleas will play the audio shriek at least these many times per minute.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
AudioShriekMaxFrequency = config.Bind<int>("Snare Flea Settings (client only)", "Audio Shriek Max Frequency", 4, new ConfigDescription("Snare Fleas will play the audio shriek at most these many times per minute.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
}
~CentipedeConfig()
{
if (LimitDamagePerClinging != null)
{
((ConfigEntryBase)LimitDamagePerClinging).ConfigFile.Remove(((ConfigEntryBase)LimitDamagePerClinging).Definition);
LimitDamagePerClinging = null;
}
if (MaxDamagePerClinging != null)
{
((ConfigEntryBase)MaxDamagePerClinging).ConfigFile.Remove(((ConfigEntryBase)MaxDamagePerClinging).Definition);
MaxDamagePerClinging = null;
}
if (PlayAudioShriekOnCeiling != null)
{
((ConfigEntryBase)PlayAudioShriekOnCeiling).ConfigFile.Remove(((ConfigEntryBase)PlayAudioShriekOnCeiling).Definition);
PlayAudioShriekOnCeiling = null;
}
if (AudioShriekMinFrequency != null)
{
((ConfigEntryBase)AudioShriekMinFrequency).ConfigFile.Remove(((ConfigEntryBase)AudioShriekMinFrequency).Definition);
AudioShriekMinFrequency = null;
}
if (AudioShriekMaxFrequency != null)
{
((ConfigEntryBase)AudioShriekMaxFrequency).ConfigFile.Remove(((ConfigEntryBase)AudioShriekMaxFrequency).Definition);
AudioShriekMaxFrequency = null;
}
}
}
[Serializable]
internal class ConfigManager : SyncedInstance<ConfigManager>
{
private ConfigFile _config = null;
public EnemyConfig Enemy { get; private set; } = null;
public SandSpiderConfig Spider { get; private set; } = null;
public CentipedeConfig Centipede { get; private set; } = null;
public ConfigFile Config
{
get
{
return _config;
}
set
{
if (_config != null || value == null)
{
Enemy = null;
Spider = null;
Centipede = null;
}
_config = value;
if (_config != null)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogDebug((object)"Binding config...");
}
_config.SaveOnConfigSet = false;
Enemy = new EnemyConfig(_config);
Spider = new SandSpiderConfig(_config);
Centipede = new CentipedeConfig(_config);
ClearOrphanedEntries(_config);
_config.Save();
_config.SaveOnConfigSet = true;
}
}
}
public ConfigManager(ConfigFile config)
{
InitInstance(this);
Config = config;
}
public static void RequestSync()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if (!SyncedInstance<ConfigManager>.IsClient)
{
return;
}
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(SyncedInstance<ConfigManager>.IntSize, (Allocator)2, -1);
try
{
SyncedInstance<ConfigManager>.MessageManager.SendNamedMessage("LCFairCompany_OnRequestConfigSync", 0uL, val, (NetworkDelivery)3);
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnRequestSync(ulong clientId, FastBufferReader _)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
if (!SyncedInstance<ConfigManager>.IsHost)
{
return;
}
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogInfo((object)$"Config sync request received from client: {clientId}");
}
byte[] array = SyncedInstance<ConfigManager>.SerializeToBytes(SyncedInstance<ConfigManager>.Instance);
int num = array.Length;
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(num + SyncedInstance<ConfigManager>.IntSize, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0);
SyncedInstance<ConfigManager>.MessageManager.SendNamedMessage("LCFairCompany_OnReceiveConfigSync", clientId, val, (NetworkDelivery)3);
}
catch (Exception arg)
{
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogError((object)$"Error occurred syncing config with client: {clientId}\n{arg}");
}
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnReceiveSync(ulong _, FastBufferReader reader)
{
//IL_0033: 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)
if (!((FastBufferReader)(ref reader)).TryBeginRead(SyncedInstance<ConfigManager>.IntSize))
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogError((object)"Config sync error: Could not begin reading buffer.");
}
return;
}
int num = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
if (!((FastBufferReader)(ref reader)).TryBeginRead(num))
{
ManualLogSource logger2 = Plugin.Logger;
if (logger2 != null)
{
logger2.LogError((object)"Config sync error: Host could not sync.");
}
return;
}
byte[] data = new byte[num];
((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
SyncedInstance<ConfigManager>.SyncInstance(data);
ManualLogSource logger3 = Plugin.Logger;
if (logger3 != null)
{
logger3.LogInfo((object)"Successfully synced config with host.");
}
}
private static void ClearOrphanedEntries(ConfigFile config)
{
PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries");
Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(config);
dictionary.Clear();
}
}
internal class EnemyConfig
{
public ConfigEntry<bool> BunkerSpiderChangeMaxCount { get; private set; } = null;
public ConfigEntry<bool> CoilheadChangePowerLevel { get; private set; } = null;
public ConfigEntry<bool> CoilheadChangeMaxCount { get; private set; } = null;
public ConfigEntry<bool> GhostGirlChangePowerLevel { get; private set; } = null;
public ConfigEntry<bool> JesterChangePowerLevel { get; private set; } = null;
public EnemyConfig(ConfigFile config)
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Expected O, but got Unknown
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Expected O, but got Unknown
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Expected O, but got Unknown
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Expected O, but got Unknown
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Expected O, but got Unknown
if (config == null)
{
throw new ArgumentNullException("config");
}
BunkerSpiderChangeMaxCount = config.Bind<bool>("Bunker Spider Settings", "Change Max Count", true, new ConfigDescription("If enabled, there can be at most 2 spiders spawned on the map (instead of 1). Do you prefer potentially having 2 spiders or other monsters? That's up to you.", (AcceptableValueBase)null, Array.Empty<object>()));
CoilheadChangePowerLevel = config.Bind<bool>("Coilhead Settings", "Change Power Level", true, new ConfigDescription("If enabled, makes it less likely to spawn (e.g. more than the Bracken but less than Hoarding Bugs).", (AcceptableValueBase)null, Array.Empty<object>()));
CoilheadChangeMaxCount = config.Bind<bool>("Coilhead Settings", "Change Max Count", true, new ConfigDescription("If enabled, there can be at most 4 coilheads spawned on the map (instead of 5).", (AcceptableValueBase)null, Array.Empty<object>()));
GhostGirlChangePowerLevel = config.Bind<bool>("Ghost Girl Settings", "Change Power Level", true, new ConfigDescription("If enabled, makes it less likely to spawn (e.g. same as the Bracken).", (AcceptableValueBase)null, Array.Empty<object>()));
JesterChangePowerLevel = config.Bind<bool>("Jester Settings", "Change Power Level", true, new ConfigDescription("If enabled, makes it more likely to spawn (e.g. more than the Bracken but less than Hoarding Bugs).", (AcceptableValueBase)null, Array.Empty<object>()));
}
~EnemyConfig()
{
if (BunkerSpiderChangeMaxCount != null)
{
((ConfigEntryBase)BunkerSpiderChangeMaxCount).ConfigFile.Remove(((ConfigEntryBase)BunkerSpiderChangeMaxCount).Definition);
BunkerSpiderChangeMaxCount = null;
}
if (CoilheadChangePowerLevel != null)
{
((ConfigEntryBase)CoilheadChangePowerLevel).ConfigFile.Remove(((ConfigEntryBase)CoilheadChangePowerLevel).Definition);
CoilheadChangePowerLevel = null;
}
if (CoilheadChangeMaxCount != null)
{
((ConfigEntryBase)CoilheadChangeMaxCount).ConfigFile.Remove(((ConfigEntryBase)CoilheadChangeMaxCount).Definition);
CoilheadChangeMaxCount = null;
}
if (GhostGirlChangePowerLevel != null)
{
((ConfigEntryBase)GhostGirlChangePowerLevel).ConfigFile.Remove(((ConfigEntryBase)GhostGirlChangePowerLevel).Definition);
GhostGirlChangePowerLevel = null;
}
if (JesterChangePowerLevel != null)
{
((ConfigEntryBase)JesterChangePowerLevel).ConfigFile.Remove(((ConfigEntryBase)JesterChangePowerLevel).Definition);
JesterChangePowerLevel = null;
}
}
}
internal class SandSpiderConfig
{
public ConfigEntry<int> Health { get; private set; } = null;
public ConfigEntry<int> Damage { get; private set; } = null;
public ConfigEntry<int> ScaleDPS { get; private set; } = null;
public SandSpiderConfig(ConfigFile config)
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Expected O, but got Unknown
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Expected O, but got Unknown
if (config == null)
{
throw new ArgumentNullException("config");
}
Health = config.Bind<int>("Bunker Spider Settings", "Health", 4, new ConfigDescription("Changes how much health the spider has. Game default: 5", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 5), Array.Empty<object>()));
Damage = config.Bind<int>("Bunker Spider Settings", "Damage", 60, new ConfigDescription("Changes how much damage the spider does per hit. Game default: 90", (AcceptableValueBase)(object)new AcceptableValueRange<int>(45, 90), Array.Empty<object>()));
ScaleDPS = config.Bind<int>("Bunker Spider Settings", "Scale DPS (%)", 75, new ConfigDescription("Allows to reduce the damage per second (i.e. how fast the spider can chain hits). Game default: 100%", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 100), Array.Empty<object>()));
}
~SandSpiderConfig()
{
if (Health != null)
{
((ConfigEntryBase)Health).ConfigFile.Remove(((ConfigEntryBase)Health).Definition);
Health = null;
}
if (Damage != null)
{
((ConfigEntryBase)Damage).ConfigFile.Remove(((ConfigEntryBase)Damage).Definition);
Damage = null;
}
if (ScaleDPS != null)
{
((ConfigEntryBase)ScaleDPS).ConfigFile.Remove(((ConfigEntryBase)ScaleDPS).Definition);
ScaleDPS = null;
}
}
}
[Serializable]
public class SyncedInstance<T>
{
[NonSerialized]
protected static int IntSize = 4;
internal static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;
internal static bool IsClient => NetworkManager.Singleton.IsClient;
internal static bool IsHost => NetworkManager.Singleton.IsHost;
public static T Default { get; private set; }
public static T Instance { get; private set; }
public static bool Synced { get; internal set; }
protected void InitInstance(T instance)
{
Default = instance;
Instance = instance;
IntSize = 4;
}
internal static void SyncInstance(byte[] data)
{
Instance = DeserializeFromBytes(data);
Synced = true;
}
internal static void RevertSync()
{
Instance = Default;
Synced = false;
}
public static byte[] SerializeToBytes(T val)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using MemoryStream memoryStream = new MemoryStream();
try
{
binaryFormatter.Serialize(memoryStream, val);
return memoryStream.ToArray();
}
catch (Exception arg)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogError((object)$"Error serializing instance: {arg}");
}
return null;
}
}
public static T DeserializeFromBytes(byte[] data)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using MemoryStream serializationStream = new MemoryStream(data);
try
{
return (T)binaryFormatter.Deserialize(serializationStream);
}
catch (Exception arg)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogError((object)$"Error deserializing instance: {arg}");
}
return default(T);
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}