Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CounterHeads v1.0.0
games.enchanted.CounterHeads.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CounterHeads.Assets; using CounterHeads.Config; using CounterHeads.Config.Value; using CounterHeads.MonoBehaviours; using CounterHeads.Networking; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; 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: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("UnityEngine")] [assembly: AssemblyCompany("games.enchanted.CounterHeads")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+027ab1420fb05abbc4091a088076dacc72e03896")] [assembly: AssemblyProduct("CounterHeads")] [assembly: AssemblyTitle("games.enchanted.CounterHeads")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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.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; } } [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 CounterHeads { [BepInPlugin("games.enchanted.CounterHeads", "CounterHeads", "1.0.0")] public class CounterHeads : BaseUnityPlugin { public static AssetBundle? AssetBundle; public static CounterHeads Instance { get; private set; } public static LocalConfig LocalConfig { get; private set; } public static SyncedConfigManager SyncedConfig { get; private set; } internal static ManualLogSource Logger { get; private set; } internal static Harmony? Harmony { get; set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; LocalConfig = new LocalConfig(((BaseUnityPlugin)this).Config); Patch(); LoadAssets(); SyncedConfig = new SyncedConfigManager(); Logger.LogInfo((object)"games.enchanted.CounterHeads v1.0.0 has loaded!"); } internal static void Patch() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("games.enchanted.CounterHeads"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); Logger.LogDebug((object)"Finished patching!"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } internal void LoadAssets() { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); if (directoryName == null) { AssetBundle = null; Logger.LogError((object)"Could not find plugin location"); } else { string assetbundlePath = Path.Combine(directoryName, "counter-heads-assets"); AssetBundleUtil.LoadAssetBundle(assetbundlePath); AssetBundle = AssetBundleUtil.GetBundle(); } } public void LogInfoIfExtendedLogging(string message) { if (LocalConfig.ExtendedLogging.Value) { Logger.LogInfo((object)message); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "games.enchanted.CounterHeads"; public const string PLUGIN_NAME = "CounterHeads"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace CounterHeads.PatchUtil { public class PatchHelper { public static void LogPatchName(string patchClass, string patchMethod) { CounterHeads.Logger.LogMessage((object)("------ Begin Patch: " + patchClass + " " + patchMethod + " ------")); } public static void PatchAndLogSurroundingIfValid(CodeMatcher match, Action<CodeMatcher> modifier, string name, int surroundingInstructions = 2) { if (!match.IsValid) { CounterHeads.Logger.LogError((object)("Code match '" + name + "' did not match against any target instructions. Some mod features may not work correctly!")); return; } CounterHeads.Logger.LogMessage((object)("-- PATCHING INSTRUCTION: " + InstructionString(match.Instruction))); CounterHeads.Logger.LogMessage((object)" -- Before Patch"); LogSurrounding(surroundingInstructions, match, " -- "); modifier(match); CounterHeads.Logger.LogMessage((object)" - - After Patch"); LogSurrounding(surroundingInstructions, match, " -- "); } public static void LogSurrounding(int surroundingInstructions, CodeMatcher match, string prefix = "") { CodeMatcher val = match.Clone(); val.Advance(-surroundingInstructions - 1); for (int i = 0; i < surroundingInstructions * 2 + 1; i++) { if (i == surroundingInstructions) { LogInstruction(val.Advance(1).Instruction, " <------ TARGET", prefix); } else { LogInstruction(val.Advance(1).Instruction, "", prefix); } } } public static void LogInstructions(IEnumerable<CodeInstruction> ins) { foreach (CodeInstruction @in in ins) { LogInstruction(@in); } } public static void LogInstruction(CodeInstruction i, string suffix = "", string prefix = "") { CounterHeads.Logger.LogMessage((object)(prefix + InstructionString(i) + suffix)); } public static string InstructionString(CodeInstruction i) { return "[ " + i.opcode.ToString() + " " + i.operand?.ToString() + " ]"; } } } namespace CounterHeads.Patches { [HarmonyPatch] internal class NetworkManagerPatch { [HarmonyPostfix] [HarmonyPatch(typeof(NetworkManager), "Initialize")] private static void AfterInitialize() { CounterHeads.Logger.LogInfo((object)"Registering Messages"); Messages.RegisterGlobalMessages(); } [HarmonyPatch(typeof(GameNetworkManager), "SetInstanceValuesBackToDefault")] [HarmonyPostfix] public static void SetInstanceValuesBackToDefault() { if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.CustomMessagingManager != null) { CounterHeads.Logger.LogInfo((object)"Unregistering Messages"); Messages.UnregisterGlobalMessages(); } } } [HarmonyPatch(typeof(EnemyAI))] public class SpringManAI_EnemyAIPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void Awake_Postfix(EnemyAI __instance) { if (!CounterHeads.SyncedConfig.ServerHasCounterHeads) { CounterHeads.Instance.LogInfoIfExtendedLogging("Awake_Postfix returning early. Server does not have counterheads installed"); return; } SpringManAI val = (SpringManAI)(object)((__instance is SpringManAI) ? __instance : null); if (!((Object)(object)val == (Object)null)) { ((Component)__instance).gameObject.AddComponent<CoilDeathTimer>(); CoilDeathTimer component = ((Component)__instance).gameObject.GetComponent<CoilDeathTimer>(); component.SetCoil(val); } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void Start_Postfix(EnemyAI __instance) { if (!CounterHeads.SyncedConfig.ServerHasCounterHeads) { CounterHeads.Instance.LogInfoIfExtendedLogging("Start_Postfix returning early. Server does not have counterheads installed"); return; } SpringManAI val = (SpringManAI)(object)((__instance is SpringManAI) ? __instance : null); if (!((Object)(object)val == (Object)null)) { int coilHealth = CounterHeads.SyncedConfig.Get().CoilHealth; if (((NetworkBehaviour)val).IsOwner && coilHealth != 3) { ((EnemyAI)val).enemyHP = coilHealth; } } } [HarmonyPatch("HitEnemy")] [HarmonyPostfix] private static void HitEnemy_Postfix(EnemyAI __instance, int force, PlayerControllerB playerWhoHit, bool playHitSFX, int hitID) { if (!CounterHeads.SyncedConfig.ServerHasCounterHeads) { CounterHeads.Instance.LogInfoIfExtendedLogging("HitEnemy_Postfix returning early. Server does not have counterheads installed"); return; } SpringManAI val = (SpringManAI)(object)((__instance is SpringManAI) ? __instance : null); if ((Object)(object)val == (Object)null || (Object)(object)playerWhoHit == (Object)null) { return; } GrabbableObject currentlyHeldObjectServer = playerWhoHit.currentlyHeldObjectServer; CounterHeads.Instance.LogInfoIfExtendedLogging($"SpringManAI hit. force: {force}, player: {playerWhoHit.playerUsername}, health: {((EnemyAI)val).enemyHP}, isDead: {((EnemyAI)val).isEnemyDead}, isOwner: {((NetworkBehaviour)val).IsOwner}, isServer: {((NetworkBehaviour)val).IsServer}, playerItem: {currentlyHeldObjectServer.itemProperties.itemName}, playerWhoHitIsClient: {((NetworkBehaviour)playerWhoHit).IsClient}, coilIsClient: {((NetworkBehaviour)val).IsClient}"); CoilDeathTimer component = ((Component)val).GetComponent<CoilDeathTimer>(); if (((EnemyAI)val).isEnemyDead || component.MarkedForDeath() || ((EnemyAI)val).enemyHP < 0) { return; } WeaponMap.Weapon? weapon = CounterHeads.SyncedConfig.Get().CoilWeapons.TryGetWeaponData(currentlyHeldObjectServer.itemProperties.itemName); if (weapon.HasValue) { int num = ((weapon.Value.GetDamage() == 0) ? force : weapon.Value.GetDamage()); ((EnemyAI)val).enemyHP = ((EnemyAI)val).enemyHP - num; CounterHeads.Instance.LogInfoIfExtendedLogging($"new health: {((EnemyAI)val).enemyHP}, damagedBy: {num}"); if (((EnemyAI)val).enemyHP <= 0 && ((NetworkBehaviour)val).IsServer && (Object)(object)component != (Object)null) { CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilPatch::HitPostfix on server: {((NetworkBehaviour)__instance).IsServer}"); component.SetDead(); } } } } } namespace CounterHeads.Networking { public static class Messages { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__ReceiveExplosionEffect; public static Action<ulong> <1>__ClientConnected; public static Action<ulong> <2>__ClientDisconnected; } public const string Global_ConfigSync = "CounterHeads_Global_ConfigSync"; public const string Global_ExplosionEffectToEveryoneMessage = "CounterHeads_Global_ExplosionEffectToEveryone"; public const string CoilDeathTimer_AudioWarningToEveryoneMessage = "CounterHeads_CoilDeathTimer_AudioWarningDurationToEveryone"; public static void RegisterGlobalMessages() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("CounterHeads_Global_ConfigSync", new HandleNamedMessageDelegate(CounterHeads.SyncedConfig.ReceiveConfigSync)); CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; object obj = <>O.<0>__ReceiveExplosionEffect; if (obj == null) { HandleNamedMessageDelegate val = CoilDeathTimer.ReceiveExplosionEffect; <>O.<0>__ReceiveExplosionEffect = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("CounterHeads_Global_ExplosionEffectToEveryone", (HandleNamedMessageDelegate)obj); NetworkManager.Singleton.OnClientConnectedCallback += ClientConnected; NetworkManager.Singleton.OnClientDisconnectCallback += ClientDisconnected; } public static void UnregisterGlobalMessages() { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("CounterHeads_Global_ExplosionEffectToEveryone"); NetworkManager.Singleton.OnClientConnectedCallback -= ClientConnected; NetworkManager.Singleton.OnClientDisconnectCallback -= ClientDisconnected; } private static void ClientConnected(ulong clientId) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) CounterHeads.Instance.LogInfoIfExtendedLogging($"Messages::ClientConnected on serer {NetworkManager.Singleton.IsServer}, clientId: {clientId}"); if (NetworkManager.Singleton.IsServer) { CounterHeads.Instance.LogInfoIfExtendedLogging($"Sending config to client {clientId}"); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, -1); SyncedConfigState syncedConfigState = CounterHeads.SyncedConfig.Get(); ((FastBufferWriter)(ref val)).WriteValue<SyncedConfigState>(ref syncedConfigState, default(ForNetworkSerializable)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("CounterHeads_Global_ConfigSync", clientId, val, (NetworkDelivery)3); } } private static void ClientDisconnected(ulong clientId) { CounterHeads.Instance.LogInfoIfExtendedLogging($"Messages::ClientDisconnected on serer {NetworkManager.Singleton.IsServer}, clientId: {clientId}"); if (!NetworkManager.Singleton.IsServer) { CounterHeads.SyncedConfig.DisconnectFromServer(); } } } } namespace CounterHeads.MonoBehaviours { public class CoilDeathTimer : NetworkBehaviour { private const float StartingPitch = 0.8f; private const float EndingPitch = 1.2f; private double _warningAudioStopAt = -1.0; private double _warningDuration = -1.0; private double _dieAt = -1.0; private SpringManAI _coil = null; private AudioSource _deathWarningSource = null; private AudioClip? _deathWarningAudio; public void Awake() { AssetBundle? assetBundle = CounterHeads.AssetBundle; _deathWarningAudio = ((assetBundle != null) ? assetBundle.LoadAsset<AudioClip>("CoilWarning") : null); } public void SetCoil(SpringManAI coil) { _coil = coil; _deathWarningSource = ((EnemyAI)_coil).creatureSFX; } public void SetDead() { if (!((NetworkBehaviour)this).IsServer) { CounterHeads.Instance.LogInfoIfExtendedLogging("CoilDeathTimer::SetDead called on a non-server"); } else if (CounterHeads.SyncedConfig.Get().CoilsExplode) { double minTimeUntilExplosion = CounterHeads.SyncedConfig.Get().MinTimeUntilExplosion; double num = (double)Random.value * (CounterHeads.SyncedConfig.Get().MaxTimeUntilExplosion - minTimeUntilExplosion) + minTimeUntilExplosion; SendAudioWarningDurationToEveryone(num); _dieAt = Time.fixedTimeAsDouble + num; if (CounterHeads.SyncedConfig.Get().CoilStunOnDeath) { _coil.SetCoilheadOnCooldownClientRpc(true); } CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilDeathTimer::SetDead on server: {((NetworkBehaviour)this).IsServer}, dieAt: {_dieAt}, warningAudioDuration: {num}"); } else { CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilDeathTimer::SetDead on server: {((NetworkBehaviour)this).IsServer}, dieAt: {_dieAt}. Explosion config disabled so we're just killing the coilhead"); KillCoil(); } } public bool MarkedForDeath() { return _dieAt >= 0.0; } public void Update() { UpdateAudio(); if (((NetworkBehaviour)this).IsServer && Object.op_Implicit((Object)(object)_coil) && MarkedForDeath() && !(Time.fixedTimeAsDouble < _dieAt)) { CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilDeathTimer::Update on server: {((NetworkBehaviour)this).IsServer}. dieAt: {_dieAt}, fixedTime: {Time.fixedTimeAsDouble}, coilExists: {_coil}"); KillCoil(); _dieAt = -1.0; } } public void KillCoil() { //IL_004c: 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_0052: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)_coil).KillEnemyOnOwnerClient(true); if (CounterHeads.SyncedConfig.Get().CoilsExplode) { float explosionRange = CounterHeads.SyncedConfig.Get().ExplosionRange; int explosionDamage = CounterHeads.SyncedConfig.Get().ExplosionDamage; Vector3 serverPosition = ((EnemyAI)_coil).serverPosition; SendExplosionEffectToEveryone(serverPosition, 1f, explosionRange, explosionDamage, 25f); } } private void UpdateAudio() { if (!(_warningAudioStopAt < 0.0)) { double num = _warningAudioStopAt - Time.fixedTimeAsDouble; double num2 = num / _warningDuration; _deathWarningSource.pitch = (float)(1.2000000476837158 * (1.0 - num2) + 0.800000011920929 * num2); if (_warningAudioStopAt <= Time.fixedTimeAsDouble) { StopPlayingAudio(); } } } private void SetupAudioLoop(double duration) { _warningDuration = duration; _warningAudioStopAt = Time.fixedTimeAsDouble + _warningDuration; _deathWarningSource.loop = true; _deathWarningSource.volume = 5f; _deathWarningSource.pitch = 0.7f; if (Object.op_Implicit((Object)(object)_deathWarningAudio)) { _deathWarningSource.clip = _deathWarningAudio; } if ((Object)(object)_deathWarningAudio != (Object)null) { _deathWarningSource.Play(); } } public void StopPlayingAudio() { if (Object.op_Implicit((Object)(object)_deathWarningSource)) { _deathWarningSource.Stop(); } } public override void OnNetworkSpawn() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown ((NetworkBehaviour)this).NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler("CounterHeads_CoilDeathTimer_AudioWarningDurationToEveryone", new HandleNamedMessageDelegate(ReceiveAudioWarningDuration)); } public override void OnNetworkDespawn() { ((NetworkBehaviour)this).NetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("CounterHeads_CoilDeathTimer_AudioWarningDurationToEveryone"); } public void SendAudioWarningDurationToEveryone(double duration) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValue<double>(ref duration, default(ForPrimitives)); ((NetworkBehaviour)this).NetworkManager.CustomMessagingManager.SendNamedMessageToAll("CounterHeads_CoilDeathTimer_AudioWarningDurationToEveryone", val, (NetworkDelivery)3); } public void ReceiveAudioWarningDuration(ulong senderId, FastBufferReader data) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) try { double num = default(double); ((FastBufferReader)(ref data)).ReadValue<double>(ref num, default(ForPrimitives)); CounterHeads.Instance.LogInfoIfExtendedLogging(string.Format("{0} received: {1}", "ReceiveAudioWarningDuration", num)); SetupAudioLoop(num); } catch (Exception arg) { CounterHeads.Logger.LogError((object)$"Exception during networking: {arg}"); } } public static void SendExplosionEffectToEveryone(Vector3 pos, float killRange, float damageRange, int nonLethalDamage, float physicsForce) { //IL_001f: 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) //IL_0032: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValue(ref pos); ((FastBufferWriter)(ref val)).WriteValue<float>(ref killRange, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue<float>(ref damageRange, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue<int>(ref nonLethalDamage, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue<float>(ref physicsForce, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("CounterHeads_Global_ExplosionEffectToEveryone", val, (NetworkDelivery)3); CounterHeads.Instance.LogInfoIfExtendedLogging($"Sent explosion effects {pos} {killRange} {damageRange} {nonLethalDamage} {physicsForce}"); } public static void ReceiveExplosionEffect(ulong senderId, FastBufferReader data) { //IL_0012: 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_0026: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) try { Vector3 val = default(Vector3); ((FastBufferReader)(ref data)).ReadValue(ref val); float num = default(float); ((FastBufferReader)(ref data)).ReadValue<float>(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref data)).ReadValue<float>(ref num2, default(ForPrimitives)); int num3 = default(int); ((FastBufferReader)(ref data)).ReadValue<int>(ref num3, default(ForPrimitives)); float num4 = default(float); ((FastBufferReader)(ref data)).ReadValue<float>(ref num4, default(ForPrimitives)); CounterHeads.Instance.LogInfoIfExtendedLogging(string.Format("{0} received: {1} {2} {3} {4} {5}", "ReceiveExplosionEffect", val, num, num2, num3, num4)); Landmine.SpawnExplosion(val, true, num, num2, num3, num4, (GameObject)null, false); } catch (Exception arg) { CounterHeads.Logger.LogError((object)$"Exception during networking: {arg}"); } } } } namespace CounterHeads.Config { public class LocalConfig { public const int ModConfigVersion = 1; private const string DamageSection = "Damage"; private const string BehaviourSection = "Behaviour"; private const string DebuggingSection = "Debugging"; public readonly ConfigEntry<int> CoilHealth = config.Bind<int>("Damage", "Coilhead health", 8, new ConfigDescription("How much health coilheads spawn with. 3 is the vanilla default, so setting this value to 3 will not modify coilhead health. This is useful if, for example, you want to use the coilhead health from another mod instead of overriding it", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 500), Array.Empty<object>())); public readonly ConfigEntry<string> CoilWeapons = config.Bind<string>("Damage", "Coilhead weapons", "{'kitchen knife':3},{'shotgun':2}", "Configure which weapons can be used against coilheads and how much damage they should deal.\nEntries are surrounded by curly brackets {} and seperated by a comma. Each entry can contain either a weapon name like so: `{'shotgun'}` (in this case the default damage amount for that item will be used), or a weapon name and damage amount seperated by a colon, like so: `{'shotgun':2}`. Weapon names should be as they appear in the top right of the screen while holding them, if the weapon name contains a `:` or `'` character, you can escape them like so: `\\:` or `\\'`\n\nAn example config to make shovels deal 2 damage and knives deal 1 could look like this: `{'shovel':2},{'kitchen knife':1}`"); public readonly ConfigEntry<bool> CoilsExplode = config.Bind<bool>("Behaviour", "Coilheads explode", true, "Whether or not coilheads explode on death. If enabled, coilheads will start playing a warning sound which will get higher pitch until eventually exploding. If disabled, coilheads will vanish on death and no warning sound will play"); public readonly ConfigEntry<bool> CoilStunOnDeath = config.Bind<bool>("Behaviour", "Stun coilheads on death", false, "Whether or not coilheads should be stunned when dealing enough damage to them. If disabled, coilheads will still be able to chase you until they explode!\nOnly takes effect when 'Coilheads explode' is enabled"); public readonly ConfigEntry<int> ExplosionDamage = config.Bind<int>("Behaviour", "Explosion damage", 60, new ConfigDescription("Maximum amount of damage coilhead explosions can inflict\nOnly takes effect when 'Coilheads explode' is enabled", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); public readonly ConfigEntry<float> ExplosionRange = config.Bind<float>("Behaviour", "Explosion range", 5f, new ConfigDescription("Furthest distance coilhead explosions can do damage from. Only takes effect when 'Coilheads explode' is enabled", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); public readonly ConfigEntry<double> MinTimeUntilExplosion = config.Bind<double>("Behaviour", "Min time until explosion", 0.6, new ConfigDescription("Minimum amount of time in seconds between dealing enough damage to a coilhead and it exploding\nOnly takes effect when 'Coilheads explode' is enabled", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.0, 20.0), Array.Empty<object>())); public readonly ConfigEntry<double> MaxTimeUntilExplosion = config.Bind<double>("Behaviour", "Max time until explosion", 1.0, new ConfigDescription("Maximum amount of time in seconds between dealing enough damage to a coilhead and it exploding\nOnly takes effect when 'Coilheads explode' is enabled", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.0, 20.0), Array.Empty<object>())); public readonly ConfigEntry<bool> ExtendedLogging = config.Bind<bool>("Debugging", "Extended logging", false, "Enable extra logging for debugging"); public LocalConfig(ConfigFile config) { }//IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown } public class SyncedConfigManager { private SyncedConfigState _currentState = SyncedConfigState.CreateFromCurrentLocal(); public bool ServerHasCounterHeads { get; private set; } = false; public SyncedConfigState Get() { return _currentState; } public void SetToServersConfig(SyncedConfigState state) { CounterHeads.Instance.LogInfoIfExtendedLogging("Recieved config state from server."); CounterHeads.SyncedConfig.Get().LogCurrentState(); _currentState = state; CounterHeads.Instance.LogInfoIfExtendedLogging("Setting to servers config"); CounterHeads.SyncedConfig.Get().LogCurrentState(); } public void ResetToLocal() { CounterHeads.Instance.LogInfoIfExtendedLogging("Resetting config back to local values"); _currentState = SyncedConfigState.CreateFromCurrentLocal(); ServerHasCounterHeads = false; CounterHeads.SyncedConfig.Get().LogCurrentState(); } public void ReceiveConfigSync(ulong id, FastBufferReader data) { ServerHasCounterHeads = true; if (NetworkManager.Singleton.IsServer) { return; } try { SyncedConfigState syncedConfigState = default(SyncedConfigState); ((FastBufferReader)(ref data)).ReadNetworkSerializable<SyncedConfigState>(ref syncedConfigState); CounterHeads.Instance.LogInfoIfExtendedLogging(string.Format("{0} received: {1}", "ReceiveConfigSync", syncedConfigState)); SetToServersConfig(syncedConfigState); } catch (Exception arg) { CounterHeads.Logger.LogError((object)$"Exception during networking: {arg}"); } } public void DisconnectFromServer() { ResetToLocal(); } } public class SyncedConfigState : INetworkSerializable { public int ServerConfigVersion; public int CoilHealth; public WeaponMap CoilWeapons; public bool CoilsExplode; public bool CoilStunOnDeath; public int ExplosionDamage; public float ExplosionRange; public double MinTimeUntilExplosion; public double MaxTimeUntilExplosion; public SyncedConfigState(int serverConfigVersion, int coilHealth, WeaponMap coilWeapons, bool coilsExplode, bool coilStunOnDeath, int explosionDamage, float explosionRange, double minTimeUntilExplosion, double maxTimeUntilExplosion) { ServerConfigVersion = serverConfigVersion; CoilHealth = coilHealth; CoilWeapons = coilWeapons; CoilsExplode = coilsExplode; CoilStunOnDeath = coilStunOnDeath; ExplosionDamage = explosionDamage; ExplosionRange = explosionRange; MinTimeUntilExplosion = minTimeUntilExplosion; MaxTimeUntilExplosion = maxTimeUntilExplosion; } public SyncedConfigState() { } public static SyncedConfigState CreateFromCurrentLocal() { return new SyncedConfigState(1, CounterHeads.LocalConfig.CoilHealth.Value, WeaponMap.ParseWeaponConfig(CounterHeads.LocalConfig.CoilWeapons.Value), CounterHeads.LocalConfig.CoilsExplode.Value, CounterHeads.LocalConfig.CoilStunOnDeath.Value, CounterHeads.LocalConfig.ExplosionDamage.Value, CounterHeads.LocalConfig.ExplosionRange.Value, CounterHeads.LocalConfig.MinTimeUntilExplosion.Value, CounterHeads.LocalConfig.MaxTimeUntilExplosion.Value); } unsafe void INetworkSerializable.NetworkSerialize<T>(BufferSerializer<T> serializer) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ServerConfigVersion, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref CoilHealth, default(ForPrimitives)); ((BufferSerializer<WeaponMap>*)(&serializer))->SerializeNetworkSerializable<WeaponMap>(ref CoilWeapons); ((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref CoilsExplode, default(ForPrimitives)); ((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref CoilStunOnDeath, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ExplosionDamage, default(ForPrimitives)); ((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref ExplosionRange, default(ForPrimitives)); ((BufferSerializer<double>*)(&serializer))->SerializeValue<double>(ref MinTimeUntilExplosion, default(ForPrimitives)); ((BufferSerializer<double>*)(&serializer))->SerializeValue<double>(ref MaxTimeUntilExplosion, default(ForPrimitives)); } public void LogCurrentState() { CounterHeads.Instance.LogInfoIfExtendedLogging("My current config state is:"); CounterHeads.Instance.LogInfoIfExtendedLogging($"ServerConfigVersion: {ServerConfigVersion}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilHealth: {CoilHealth}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilWeapons: {CoilWeapons}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilsExplode: {CoilsExplode}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"CoilStunOnDeath: {CoilStunOnDeath}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"ExplosionDamage: {ExplosionDamage}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"ExplosionRange: {ExplosionRange}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"MinTimeUntilExplosion: {MinTimeUntilExplosion}"); CounterHeads.Instance.LogInfoIfExtendedLogging($"MaxTimeUntilExplosion: {MaxTimeUntilExplosion}"); CounterHeads.Instance.LogInfoIfExtendedLogging("------"); } } } namespace CounterHeads.Config.Value { public class WeaponMap : INetworkSerializable { public struct Weapon : INetworkSerializable { private string _name; private int _damage; internal Weapon(string name, int damage) { _name = name.ToLowerInvariant(); _damage = damage; } public int GetDamage() { return _damage; } internal bool NameMatches(string weaponNameLower) { return _name.Equals(weaponNameLower); } unsafe void INetworkSerializable.NetworkSerialize<T>(BufferSerializer<T> bufferSerializer) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) bufferSerializer.SerializeValue(ref _name, false); ((BufferSerializer<int>*)(&bufferSerializer))->SerializeValue<int>(ref _damage, default(ForPrimitives)); } } private Weapon[] _weapons; public WeaponMap(IEnumerable<Weapon> weapons) { _weapons = weapons.ToArray(); } public WeaponMap() { _weapons = Array.Empty<Weapon>(); } public static WeaponMap ParseWeaponConfig(string configString) { string input = configString.Replace("\\:", "$_colonesc_$").Replace("\\,", "$_commaesc_$"); List<Weapon> list = new List<Weapon>(); Match match = Regex.Match(input, "(?:\\{'([^']*)'):([0-9]*)}|(?:\\{'([^']*)'})", RegexOptions.IgnoreCase | RegexOptions.Compiled, TimeSpan.FromSeconds(2.0)); if (!match.Success) { CounterHeads.Logger.LogWarning((object)("No valid values to parse from weapon map, " + configString)); return new WeaponMap(Array.Empty<Weapon>()); } while (match.Success) { if (match.Groups[3].Success) { string value = match.Groups[3].Value; value = value.Replace("$_commaesc_$", ",").Replace("$_colonesc_$", ":"); if (CheckIfWeaponAlreadyPresent(list, value)) { CounterHeads.Logger.LogWarning((object)("Weapon '" + value + "' was listed multiple times in config, only the first entry will be used")); match = match.NextMatch(); continue; } list.Add(new Weapon(match.Groups[3].Value, 0)); CounterHeads.Instance.LogInfoIfExtendedLogging($"Found weapon with no damage at {match.Groups[3].Index}. Group 3 value: {value}, Match value: {match.Value}"); } else if (match.Groups[1].Success && match.Groups[2].Success) { string value2 = match.Groups[1].Value; value2 = value2.Replace("$_commaesc_$", ",").Replace("$_colonesc_$", ":"); if (CheckIfWeaponAlreadyPresent(list, value2)) { CounterHeads.Logger.LogWarning((object)("Weapon '" + value2 + "' was listed multiple times in config, only the first entry will be used")); match = match.NextMatch(); continue; } list.Add(new Weapon(value2, int.Parse(match.Groups[2].Value, NumberStyles.Integer))); CounterHeads.Instance.LogInfoIfExtendedLogging($"Found weapon with damage at {match.Groups[1].Index} and {match.Groups[2].Index}. Group 1 value: {value2}, Group 2 value: {match.Groups[2].Value}, Match value: {match.Value}"); } else { CounterHeads.Logger.LogWarning((object)"No groups matched"); } match = match.NextMatch(); } return new WeaponMap(list); } private static bool CheckIfWeaponAlreadyPresent(List<Weapon> weapons, string name) { foreach (Weapon weapon in weapons) { if (weapon.NameMatches(name.ToLowerInvariant())) { return true; } } return false; } public Weapon? TryGetWeaponData(string name) { Weapon[] weapons = _weapons; for (int i = 0; i < weapons.Length; i++) { Weapon value = weapons[i]; if (value.NameMatches(name.ToLowerInvariant())) { return value; } } return null; } unsafe void INetworkSerializable.NetworkSerialize<T>(BufferSerializer<T> serializer) { //IL_0028: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) int num = 0; Weapon[] array = new Weapon[num]; if (serializer.IsWriter) { array = _weapons; num = array.Length; } ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref num, default(ForPrimitives)); if (!serializer.IsWriter) { array = new Weapon[num]; } for (int i = 0; i < num; i++) { ((BufferSerializer<Weapon>*)(&serializer))->SerializeValue<Weapon>(ref array[i], default(ForNetworkSerializable)); } if (serializer.IsReader) { _weapons = array; } } } } namespace CounterHeads.Assets { public static class AssetBundleUtil { internal static AssetBundle MainAssetBundle; internal static void LoadAssetBundle(string assetbundlePath) { if ((Object)(object)MainAssetBundle == (Object)null) { MainAssetBundle = AssetBundle.LoadFromFile(assetbundlePath); } } internal static AssetBundle? GetBundle() { if (Object.op_Implicit((Object)(object)MainAssetBundle)) { return MainAssetBundle; } Debug.LogError((object)"There is no AssetBundle to load assets from."); return null; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }