Decompiled source of PredictableEggs v1.0.0

PredictableEggs.dll

Decompiled a month ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CSync.Extensions;
using CSync.Lib;
using CessilCellsCeaChells.CeaChore;
using IL;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using On;
using PredictableEggs.NetcodePatcher;
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: RequiresMethod(typeof(StunGrenadeItem), "Awake", typeof(void), new Type[] { })]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PredictableEggs")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A mod for Lethal Company")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a889cc02d7552efb56dd330b9a80d141d4900cb3")]
[assembly: AssemblyProduct("PredictableEggs")]
[assembly: AssemblyTitle("PredictableEggs")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
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 PredictableEggs
{
	public static class Assets
	{
		public static AudioClip EggReadyToExplode { get; private set; }

		public static void Load()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			AssetBundle val = AssetBundle.LoadFromFile(Path.Combine(directoryName, "predictableeggs.bundle"));
			EggReadyToExplode = val.LoadAsset<AudioClip>("EggReadyToExplode");
		}
	}
	public class Config : SyncedConfig2<Config>
	{
		[SyncedEntryField]
		public SyncedEntry<float> EggExplodeChance;

		[SyncedEntryField]
		public SyncedEntry<bool> WarningSound;

		[SyncedEntryField]
		public SyncedEntry<bool> DontExplodeOnDrop;

		[SyncedEntryField]
		public SyncedEntry<bool> FixHitGround;

		public Config(ConfigFile cfg)
			: base("moe.sylvi.PredictableEggs")
		{
			EggExplodeChance = SyncedBindingExtensions.BindSyncedEntry<float>(cfg, "General", "EggExplodeChance", 16f, "Percentage chance for the egg to explode, determined when the egg is selected in the inventory. (Vanilla value is 16%)");
			WarningSound = SyncedBindingExtensions.BindSyncedEntry<bool>(cfg, "General", "WarningSound", true, "Plays a unique sound (fizzling) if the egg will explode on its next throw.");
			DontExplodeOnDrop = SyncedBindingExtensions.BindSyncedEntry<bool>(cfg, "General", "DontExplodeOnDrop", true, "Prevents eggs from exploding when dropped, as opposed to being thrown.");
			FixHitGround = SyncedBindingExtensions.BindSyncedEntry<bool>(cfg, "Technical", "FixHitGround", true, "Fixes a bug where items hitting the ground might not register properly, making no sound and not exploding eggs. Keep enabled unless any issues occur.");
			ConfigManager.Register<Config>((SyncedConfig2<Config>)this);
		}
	}
	public static class Patches
	{
		private delegate void StunGrenadeItem_orig_Awake(StunGrenadeItem self);

		[CompilerGenerated]
		private static class <>O
		{
			public static hook_EquipItem <0>__StunGrenadeItem_EquipItem;

			public static hook_DiscardItem <1>__StunGrenadeItem_DiscardItem;

			public static hook_ItemActivate <2>__StunGrenadeItem_ItemActivate;

			public static hook_OnHitGround <3>__StunGrenadeItem_OnHitGround;

			public static Manipulator <4>__GrabbableObject_Update_IL;
		}

		public static void Initialize()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0053: 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: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			object obj = <>O.<0>__StunGrenadeItem_EquipItem;
			if (obj == null)
			{
				hook_EquipItem val = StunGrenadeItem_EquipItem;
				<>O.<0>__StunGrenadeItem_EquipItem = val;
				obj = (object)val;
			}
			StunGrenadeItem.EquipItem += (hook_EquipItem)obj;
			object obj2 = <>O.<1>__StunGrenadeItem_DiscardItem;
			if (obj2 == null)
			{
				hook_DiscardItem val2 = StunGrenadeItem_DiscardItem;
				<>O.<1>__StunGrenadeItem_DiscardItem = val2;
				obj2 = (object)val2;
			}
			StunGrenadeItem.DiscardItem += (hook_DiscardItem)obj2;
			object obj3 = <>O.<2>__StunGrenadeItem_ItemActivate;
			if (obj3 == null)
			{
				hook_ItemActivate val3 = StunGrenadeItem_ItemActivate;
				<>O.<2>__StunGrenadeItem_ItemActivate = val3;
				obj3 = (object)val3;
			}
			StunGrenadeItem.ItemActivate += (hook_ItemActivate)obj3;
			object obj4 = <>O.<3>__StunGrenadeItem_OnHitGround;
			if (obj4 == null)
			{
				hook_OnHitGround val4 = StunGrenadeItem_OnHitGround;
				<>O.<3>__StunGrenadeItem_OnHitGround = val4;
				obj4 = (object)val4;
			}
			StunGrenadeItem.OnHitGround += (hook_OnHitGround)obj4;
			object obj5 = <>O.<4>__GrabbableObject_Update_IL;
			if (obj5 == null)
			{
				Manipulator val5 = GrabbableObject_Update_IL;
				<>O.<4>__GrabbableObject_Update_IL = val5;
				obj5 = (object)val5;
			}
			GrabbableObject.Update += (Manipulator)obj5;
			new Hook((MethodBase)typeof(StunGrenadeItem).GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public), typeof(Patches).GetMethod("StunGrenadeItem_Awake", BindingFlags.Static | BindingFlags.NonPublic)).Apply();
		}

		private static void GrabbableObject_Update_IL(ILContext il)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			if (!val.TryGotoNext((MoveType)1, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchLdcR4(instr, 0.1f)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GrabbableObject.Update @ Check fall distance");
				return;
			}
			val.EmitDelegate<Func<float, float>>((Func<float, float>)((float value) => Plugin.Config.FixHitGround.Value ? Math.Abs(value) : value));
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchStfld<GrabbableObject>(instr, "reachedFloorTarget")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GrabbableObject.Update @ Reached floor target");
				return;
			}
			val.Emit(OpCodes.Ldarg_0);
			val.EmitDelegate<Action<GrabbableObject>>((Action<GrabbableObject>)delegate(GrabbableObject self)
			{
				if (Plugin.Config.FixHitGround.Value && !self.hasHitGround)
				{
					self.PlayDropSFX();
					self.OnHitGround();
				}
			});
		}

		private static void StunGrenadeItem_OnHitGround(orig_OnHitGround orig, StunGrenadeItem self)
		{
			Plugin.Logger.LogInfo((object)$"Hit ground! Will explode: {self.explodeOnThrow}");
			orig.Invoke(self);
		}

		private static void StunGrenadeItem_ItemActivate(orig_ItemActivate orig, StunGrenadeItem self, bool used, bool buttonDown)
		{
			if (!self.inPullingPinAnimation && self.pinPulled && ((NetworkBehaviour)self).IsOwner)
			{
				PredictableEggComponent component = ((Component)self).gameObject.GetComponent<PredictableEggComponent>();
				component.WasThrown = true;
			}
			orig.Invoke(self, used, buttonDown);
		}

		private static void StunGrenadeItem_EquipItem(orig_EquipItem orig, StunGrenadeItem self)
		{
			if (self.chanceToExplode >= 100f)
			{
				orig.Invoke(self);
				return;
			}
			float chanceToExplode = self.chanceToExplode;
			self.chanceToExplode = 100f;
			orig.Invoke(self);
			self.chanceToExplode = chanceToExplode;
			PredictableEggComponent component = ((Component)self).gameObject.GetComponent<PredictableEggComponent>();
			component.SetExplosiveOnEquip();
			component.WasThrown = false;
			self.gotExplodeOnThrowRPC = true;
		}

		private static void StunGrenadeItem_DiscardItem(orig_DiscardItem orig, StunGrenadeItem self)
		{
			if (SyncedEntry<bool>.op_Implicit(Plugin.Config.DontExplodeOnDrop) && (((NetworkBehaviour)self).IsOwner || ((GrabbableObject)self).wasOwnerLastFrame) && (Object)(object)((GrabbableObject)self).playerHeldBy != (Object)null && !((GrabbableObject)self).playerHeldBy.isPlayerDead && self.chanceToExplode < 100f)
			{
				PredictableEggComponent component = ((Component)self).gameObject.GetComponent<PredictableEggComponent>();
				if (!component.WasThrown)
				{
					Plugin.Logger.LogInfo((object)"Dropping safely!");
					self.explodeOnThrow = false;
					component.SetExplodeOnThrowDirectServerRpc(explode: false);
				}
			}
			orig.Invoke(self);
		}

		private static void StunGrenadeItem_Awake(StunGrenadeItem_orig_Awake orig, StunGrenadeItem self)
		{
			orig(self);
			if (!Object.op_Implicit((Object)(object)((Component)self).gameObject.GetComponent<PredictableEggComponent>()))
			{
				((Component)self).gameObject.AddComponent<PredictableEggComponent>();
			}
		}
	}
	[BepInPlugin("moe.sylvi.PredictableEggs", "PredictableEggs", "1.0.0")]
	[BepInDependency("com.sigurd.csync", "5.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public static Config Config { get; private set; }

		public static ManualLogSource Logger { get; private set; }

		private void Awake()
		{
			Config = new Config(((BaseUnityPlugin)this).Config);
			Logger = ((BaseUnityPlugin)this).Logger;
			Assets.Load();
			Patches.Initialize();
			InitNetcodePatcher();
			Logger.LogInfo((object)"Plugin moe.sylvi.PredictableEggs is loaded!");
		}

		private void InitNetcodePatcher()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			Type[] array = types;
			foreach (Type type in array)
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo[] array2 = methods;
				foreach (MethodInfo methodInfo in array2)
				{
					object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
					if (customAttributes.Length != 0)
					{
						methodInfo.Invoke(null, null);
					}
				}
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "moe.sylvi.PredictableEggs";

		public const string PLUGIN_NAME = "PredictableEggs";

		public const string PLUGIN_VERSION = "1.0.0";
	}
	public class PredictableEggComponent : NetworkBehaviour
	{
		public bool WasThrown = false;

		private StunGrenadeItem eggItem;

		private void Awake()
		{
			eggItem = ((Component)this).gameObject.GetComponent<StunGrenadeItem>();
		}

		public void SetExplosiveOnEquip()
		{
			//IL_0027: 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 (((NetworkBehaviour)this).IsOwner)
			{
				Random random = new Random(StartOfRound.Instance.randomMapSeed + 10 + (int)((Component)this).transform.position.x + (int)((Component)this).transform.position.z);
				bool flag = random.NextDouble() * 100.0 < (double)Plugin.Config.EggExplodeChance.Value;
				if (flag && Plugin.Config.WarningSound.Value)
				{
					((Component)this).gameObject.GetComponent<AudioSource>().PlayOneShot(Assets.EggReadyToExplode, 1f);
				}
				Plugin.Logger.LogInfo((object)$"Egg explosion prediction: {flag}");
				eggItem.explodeOnThrow = flag;
				SetExplodeOnThrowDirectServerRpc(flag);
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void SetExplodeOnThrowDirectServerRpc(bool explode)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(1866835474u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref explode, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 1866835474u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					SetExplodeOnThrowDirectClientRpc(explode);
				}
			}
		}

		[ClientRpc]
		public void SetExplodeOnThrowDirectClientRpc(bool explode)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val = default(ClientRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(1435201353u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref explode, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendClientRpc(ref val2, 1435201353u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && !((NetworkBehaviour)this).IsOwner)
				{
					Plugin.Logger.LogInfo((object)$"Egg explosion prediction: {explode}");
					eggItem.gotExplodeOnThrowRPC = true;
					eggItem.explodeOnThrow = explode;
				}
			}
		}

		protected override void __initializeVariables()
		{
			((NetworkBehaviour)this).__initializeVariables();
		}

		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeRPCS_PredictableEggComponent()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			NetworkManager.__rpc_func_table.Add(1866835474u, new RpcReceiveHandler(__rpc_handler_1866835474));
			NetworkManager.__rpc_func_table.Add(1435201353u, new RpcReceiveHandler(__rpc_handler_1435201353));
		}

		private static void __rpc_handler_1866835474(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				bool explodeOnThrowDirectServerRpc = default(bool);
				((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref explodeOnThrowDirectServerRpc, default(ForPrimitives));
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((PredictableEggComponent)(object)target).SetExplodeOnThrowDirectServerRpc(explodeOnThrowDirectServerRpc);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_1435201353(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				bool explodeOnThrowDirectClientRpc = default(bool);
				((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref explodeOnThrowDirectClientRpc, default(ForPrimitives));
				target.__rpc_exec_stage = (__RpcExecStage)2;
				((PredictableEggComponent)(object)target).SetExplodeOnThrowDirectClientRpc(explodeOnThrowDirectClientRpc);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		protected internal override string __getTypeName()
		{
			return "PredictableEggComponent";
		}
	}
}
namespace PredictableEggs.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}