Decompiled source of LC GiftBox Config v1.1.1
plugins/Xilophor.StaticNetcodeLib.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using OdinSerializer; using StaticNetcodeLib.Enums; using StaticNetcodeLib.Messaging; using StaticNetcodeLib.Patches; using StaticNetcodeLib.Serialization; using Unity.Collections; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: RegisterFormatterLocator(typeof(INetworkSerializableFormatterLocator), -100)] [assembly: RegisterFormatter(typeof(NetworkBehaviourReferenceFormatter), 0)] [assembly: RegisterFormatter(typeof(NetworkObjectReferenceFormatter), 0)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: AssemblyCompany("xilophor")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1+c96b5d48308fd38bea459d210122948477bffeb9")] [assembly: AssemblyProduct("StaticNetcodeLib")] [assembly: AssemblyTitle("Xilophor.StaticNetcodeLib")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Xilophor/StaticNetcodeLib")] [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 StaticNetcodeLib { [AttributeUsage(AttributeTargets.Class)] public class StaticNetcodeAttribute : Attribute { } [BepInPlugin("Xilophor.StaticNetcodeLib", "StaticNetcodeLib", "1.1.1")] public class StaticNetcodeLib : BaseUnityPlugin { public const string Guid = "Xilophor.StaticNetcodeLib"; private static readonly HarmonyMethod ServerRpcPatch = new HarmonyMethod(typeof(RpcPatcher), "PatchServerRpc", (Type[])null); private static readonly HarmonyMethod ClientRpcPatch = new HarmonyMethod(typeof(RpcPatcher), "PatchClientRpc", (Type[])null); public static StaticNetcodeLib Instance { get; private set; } = null; internal static ManualLogSource Logger { get; private set; } = null; internal static Harmony? Harmony { get; private set; } private void Awake() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; Instance = this; Patch(); GameObject gameObject = ((Component)this).gameObject; ((Object)gameObject).hideFlags = (HideFlags)(((Object)gameObject).hideFlags | 0x3D); Logger.LogInfo((object)"Xilophor.StaticNetcodeLib v1.1.1 has loaded!"); } private static void Patch() { //IL_000c: 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_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("Xilophor.StaticNetcodeLib"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); Logger.LogDebug((object)"Finished patching!"); } private void Start() { IEnumerable<Type> source = from info in Chainloader.PluginInfos.Values where info.Instance != null select ((object)info.Instance).GetType() into type where ((MemberInfo)type).GetCustomAttributes<BepInDependency>().Any((BepInDependency attr) => attr.DependencyGUID == "Xilophor.StaticNetcodeLib") select type; Type[] source2 = source.SelectMany((Type plugin) => from type in plugin.Assembly.GetTypes() where type.GetCustomAttributes<StaticNetcodeAttribute>().Any() select type).ToArray(); MethodInfo[] source3 = source2.SelectMany((Type type) => type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)).ToArray(); IEnumerable<MethodInfo> enumerable = source3.Where((MethodInfo method) => ((MemberInfo)method).GetCustomAttributes<ServerRpcAttribute>().Any() && method.IsStatic); IEnumerable<MethodInfo> enumerable2 = source3.Where((MethodInfo method) => ((MemberInfo)method).GetCustomAttributes<ClientRpcAttribute>().Any() && method.IsStatic); CollectionExtensions.Do<MethodInfo>(enumerable, (Action<MethodInfo>)delegate(MethodInfo method) { if (!method.Name.EndsWith("ServerRpc")) { Logger.LogError((object)("Method " + GeneralExtensions.FullDescription((MethodBase)method) + " must end with ServerRpc.")); return; } try { Harmony? harmony2 = Harmony; if (harmony2 != null) { harmony2.Patch((MethodBase)method, ServerRpcPatch, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } RpcPatcher.RpcExecStageLookup[method] = RpcExecStage.None; } catch { Logger.LogError((object)("Unable to patch the method " + GeneralExtensions.FullDescription((MethodBase)method) + "!")); } }); CollectionExtensions.Do<MethodInfo>(enumerable2, (Action<MethodInfo>)delegate(MethodInfo method) { if (!method.Name.EndsWith("ClientRpc")) { Logger.LogError((object)("Method " + GeneralExtensions.FullDescription((MethodBase)method) + " must end with ClientRpc.")); return; } try { Harmony? harmony = Harmony; if (harmony != null) { harmony.Patch((MethodBase)method, ClientRpcPatch, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } RpcPatcher.RpcExecStageLookup[method] = RpcExecStage.None; } catch { Logger.LogError((object)("Unable to patch the method " + GeneralExtensions.FullDescription((MethodBase)method) + "!")); } }); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Xilophor.StaticNetcodeLib"; public const string PLUGIN_NAME = "StaticNetcodeLib"; public const string PLUGIN_VERSION = "1.1.1"; } } namespace StaticNetcodeLib.Serialization { public class INetworkSerializableFormatter<T> : MinimalBaseFormatter<T> where T : INetworkSerializable { private readonly Serializer<byte[]> _byteArraySerializer = Serializer.Get<byte[]>(); protected override void Read(ref T value, IDataReader reader) { //IL_001a: 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_0026: Unknown result type (might be due to invalid IL or missing references) byte[] array = _byteArraySerializer.ReadValue(reader); FastBufferReader val = default(FastBufferReader); ((FastBufferReader)(ref val))..ctor(array, (Allocator)2, -1, 0); BufferSerializer<BufferSerializerReader> val2 = default(BufferSerializer<BufferSerializerReader>); val2..ctor(new BufferSerializerReader(val)); ((INetworkSerializable)value).NetworkSerialize<BufferSerializerReader>(val2); } protected override void Write(ref T value, IDataWriter writer) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, 65536); BufferSerializer<BufferSerializerWriter> val2 = default(BufferSerializer<BufferSerializerWriter>); val2..ctor(new BufferSerializerWriter(val)); ((INetworkSerializable)value).NetworkSerialize<BufferSerializerWriter>(val2); Serializer<byte[]> byteArraySerializer = _byteArraySerializer; FastBufferWriter fastBufferWriter = val2.GetFastBufferWriter(); byteArraySerializer.WriteValue(((FastBufferWriter)(ref fastBufferWriter)).ToArray(), writer); } } public class INetworkSerializableFormatterLocator : IFormatterLocator { public bool TryGetFormatter(Type type, FormatterLocationStep step, ISerializationPolicy policy, bool allowWeakFallbackFormatters, out IFormatter formatter) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if ((int)step != 1 || !typeof(INetworkSerializable).IsAssignableFrom(type)) { formatter = null; return false; } try { formatter = (IFormatter)Activator.CreateInstance(typeof(INetworkSerializableFormatter<>).MakeGenericType(type)); } catch (Exception ex) { if (!allowWeakFallbackFormatters || (!(ex is ExecutionEngineException) && !(ex.GetBaseException() is ExecutionEngineException))) { throw; } formatter = (IFormatter)new WeakSerializableFormatter(type); } return true; } } public class NetworkBehaviourReferenceFormatter : MinimalBaseFormatter<NetworkBehaviourReference> { private static readonly Serializer<ushort> UInt16Serializer = Serializer.Get<ushort>(); private static readonly Serializer<NetworkObjectReference> NetworkObjectReferenceSerializer = Serializer.Get<NetworkObjectReference>(); protected override void Read(ref NetworkBehaviourReference value, IDataReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) value.m_NetworkObjectReference = NetworkObjectReferenceSerializer.ReadValue(reader); value.m_NetworkBehaviourId = UInt16Serializer.ReadValue(reader); } protected override void Write(ref NetworkBehaviourReference value, IDataWriter writer) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) NetworkObjectReferenceSerializer.WriteValue(value.m_NetworkObjectReference, writer); UInt16Serializer.WriteValue(value.m_NetworkBehaviourId, writer); } } internal class NetworkObjectReferenceFormatter : MinimalBaseFormatter<NetworkObjectReference> { private static readonly Serializer<ulong> UInt64Serializer = Serializer.Get<ulong>(); protected override void Read(ref NetworkObjectReference value, IDataReader reader) { ((NetworkObjectReference)(ref value)).NetworkObjectId = UInt64Serializer.ReadValue(reader); } protected override void Write(ref NetworkObjectReference value, IDataWriter writer) { UInt64Serializer.WriteValue(((NetworkObjectReference)(ref value)).NetworkObjectId, writer); } } } namespace StaticNetcodeLib.Patches { [HarmonyPatch(typeof(NetworkManager))] [HarmonyPriority(500)] [HarmonyWrapSafe] internal static class NetworkManagerPatch { [HarmonyPatch("Initialize")] [HarmonyPostfix] public static void InitializePatch() { new UnnamedMessageHandler(); } [HarmonyPatch("Shutdown")] [HarmonyPrefix] public static void ShutdownPatch() { UnnamedMessageHandler.Instance?.Dispose(); } } internal class RpcPatcher { internal static Dictionary<MethodBase, RpcExecStage> RpcExecStageLookup { get; } = new Dictionary<MethodBase, RpcExecStage>(); public static bool PatchServerRpc(MethodBase __originalMethod, object[] __args) { if (!IsListening(out NetworkManager networkManager)) { return false; } RpcExecStage rpcExecStage = RpcExecStageLookup[__originalMethod]; if (rpcExecStage == RpcExecStage.Server) { return true; } if (!networkManager.IsClient && !networkManager.IsHost) { return false; } SendServerRpc(__originalMethod, ref __args); return false; } public static bool PatchClientRpc(MethodBase __originalMethod, object[]? __args) { if (!IsListening(out NetworkManager networkManager)) { return false; } RpcExecStage rpcExecStage = RpcExecStageLookup[__originalMethod]; if (rpcExecStage == RpcExecStage.Client) { return true; } if (!networkManager.IsHost && !networkManager.IsServer) { return false; } SendClientRpc(__originalMethod, __args); return false; } private static bool IsListening(out NetworkManager? networkManager) { networkManager = NetworkManager.Singleton; if ((Object)(object)networkManager != (Object)null && networkManager.IsListening) { return UnnamedMessageHandler.Instance != null; } return false; } private static void SendServerRpc(MethodBase __originalMethod, ref object[] __args) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!IsListening(out NetworkManager networkManager)) { return; } MessageData messageData = new MessageData(MessageType.ServerRpc, __originalMethod, __args); for (int num = __args.Length - 1; num >= 0; num--) { if (__args[num] is ServerRpcParams val) { val.Receive.SenderClientId = networkManager.LocalClientId; __args[num] = val; break; } } UnnamedMessageHandler.Instance.SendMessageToServer(messageData); } private static void SendClientRpc(MethodBase __originalMethod, object[]? __args) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (!IsListening(out NetworkManager _)) { return; } MessageData messageData = new MessageData(MessageType.ClientRpc, __originalMethod, __args); if (__args == null || __args.Length == 0 || !__args.Any((object arg) => arg is ClientRpcParams)) { UnnamedMessageHandler.Instance.SendMessageToClient(messageData); return; } ClientRpcParams clientRpcParams = (ClientRpcParams)__args.FirstOrDefault((object arg) => arg is ClientRpcParams); UnnamedMessageHandler.Instance.SendMessageToClient(messageData, clientRpcParams); } } } namespace StaticNetcodeLib.Messaging { public record MessageData([property: OdinSerialize] MessageType MessageType, [property: OdinSerialize] MethodBase MethodBase, [property: OdinSerialize] object? Data) { public (MessageType, MethodBase, object?) AsValueTuple() { return (MessageType, MethodBase, Data); } } internal class UnnamedMessageHandler : IDisposable { private const string LibIdentifier = "StaticNetcodeLib"; private static readonly SerializationContext DefaultSerializationContext = new SerializationContext { Config = new SerializationConfig { SerializationPolicy = SerializationPolicies.Everything } }; private static readonly DeserializationContext DefaultDeserializationContext = new DeserializationContext { Config = new SerializationConfig { SerializationPolicy = SerializationPolicies.Everything } }; internal static UnnamedMessageHandler? Instance { get; private set; } private NetworkManager NetworkManager { get; } private CustomMessagingManager CustomMessagingManager { get; } internal UnnamedMessageHandler() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown Instance = this; NetworkManager = NetworkManager.Singleton; CustomMessagingManager = NetworkManager.CustomMessagingManager; CustomMessagingManager.OnUnnamedMessage += new UnnamedMessageDelegate(ReceiveMessage); } internal void SendMessageToClient(MessageData messageData, ClientRpcParams clientRpcParams = default(ClientRpcParams)) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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) WriteMessageData(out var writer, messageData); IReadOnlyList<ulong> readOnlyList = clientRpcParams.Send.TargetClientIds ?? clientRpcParams.Send.TargetClientIdsNativeArray.GetValueOrDefault().ToArray(); if (readOnlyList.Any((ulong client) => client == 0)) { readOnlyList = readOnlyList.Where((ulong client) => client != 0) as IReadOnlyList<ulong>; FastBufferReader message = default(FastBufferReader); ((FastBufferReader)(ref message))..ctor(writer, (Allocator)2, -1, 0, (Allocator)2); try { ReceiveMessage(0uL, message); if ((readOnlyList == null || readOnlyList.Count == 0) ? true : false) { ((FastBufferWriter)(ref writer)).Dispose(); return; } } finally { ((IDisposable)(FastBufferReader)(ref message)).Dispose(); } } if (readOnlyList.Any()) { CustomMessagingManager.SendUnnamedMessage(readOnlyList, writer, (NetworkDelivery)4); } else { CustomMessagingManager.SendUnnamedMessageToAll(writer, (NetworkDelivery)4); } ((FastBufferWriter)(ref writer)).Dispose(); } internal void SendMessageToServer(MessageData messageData) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) WriteMessageData(out var writer, messageData); CustomMessagingManager.SendUnnamedMessage(0uL, writer, (NetworkDelivery)4); ((FastBufferWriter)(ref writer)).Dispose(); } private void ReceiveMessage(ulong clientId, FastBufferReader message) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) string text = default(string); ((FastBufferReader)(ref message)).ReadValueSafe(ref text, false); if (!(text != "StaticNetcodeLib")) { byte[] serializedData = default(byte[]); ((FastBufferReader)(ref message)).ReadValueSafe<byte>(ref serializedData, default(ForPrimitives)); MessageData messageData = DeserializeMessageData(serializedData); switch (messageData.MessageType) { case MessageType.ServerRpc: case MessageType.ClientRpc: ReceiveRpc(messageData); break; case MessageType.Variable: throw new NotImplementedException(); default: throw new ArgumentOutOfRangeException(); } } } private void ReceiveRpc(MessageData messageData) { (MessageType, MethodBase, object?) tuple = messageData.AsValueTuple(); MethodBase item = tuple.Item2; object item2 = tuple.Item3; item = item ?? throw new NullReferenceException("MethodBase is null."); object[] array = (object[])item2; object[] parameters = ((array != null && array.Length == 0) ? null : ((object[])item2)); RpcExecStage value = ((messageData.MessageType == MessageType.ServerRpc) ? RpcExecStage.Server : RpcExecStage.Client); RpcPatcher.RpcExecStageLookup[item] = value; item.Invoke(null, parameters); RpcPatcher.RpcExecStageLookup[item] = RpcExecStage.None; } private static byte[] Serialize(object? data) { return SerializationUtility.SerializeValue<object>(data, (DataFormat)0, DefaultSerializationContext); } private static byte[] SerializeMessageData(MessageData messageData) { return SerializationUtility.SerializeValue<MessageData>(messageData with { Data = Serialize(messageData.Data) }, (DataFormat)0, (SerializationContext)null); } private static T Deserialize<T>(byte[] serializedData) { return SerializationUtility.DeserializeValue<T>(serializedData, (DataFormat)0, DefaultDeserializationContext); } private static MessageData DeserializeMessageData(byte[] serializedData) { MessageData messageData = SerializationUtility.DeserializeValue<MessageData>(serializedData, (DataFormat)0, (DeserializationContext)null); return messageData with { Data = Deserialize<object[]>((byte[])messageData.Data) }; } private static void WriteMessageData(out FastBufferWriter writer, MessageData messageData) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) (byte[], int) tuple = SerializeDataAndGetSize(messageData); byte[] item = tuple.Item1; int item2 = tuple.Item2; writer = new FastBufferWriter(item2, (Allocator)2, -1); ((FastBufferWriter)(ref writer)).WriteValueSafe("StaticNetcodeLib", false); ((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(item, default(ForPrimitives)); } private static (byte[], int) SerializeDataAndGetSize(MessageData messageData) { int num = 0; byte[] array = SerializeMessageData(messageData); num += Encoding.UTF8.GetByteCount("StaticNetcodeLib"); num += array.Length; num += 100; return (array, num); } public void Dispose() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown CustomMessagingManager.OnUnnamedMessage -= new UnnamedMessageDelegate(ReceiveMessage); } } } namespace StaticNetcodeLib.Enums { public enum MessageType { ServerRpc, ClientRpc, Variable } internal enum RpcExecStage { None, Server, Client } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } internal static class IsExternalInit { } }
plugins/LC_GiftBox_Config.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LC_GiftBox_Config.libs.HarmonyXExtensions; using LC_GiftBox_Config.libs.ILStepper; using LC_GiftBox_Config.libs.LethalConfigNicerizer; using LC_GiftBox_Config.libs.Probability; using LethalConfig; using LethalConfig.ConfigItems; using Microsoft.CodeAnalysis; using StaticNetcodeLib; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("DBJ")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Configure gift boxes / presents, such as having store items / scrap / another present / nothing, weighting of item selection, spawn rates, etc.")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1+704f2e95fca5e8ab734e8c24eac0aa86477ce5d3")] [assembly: AssemblyProduct("LC_GiftBox_Config")] [assembly: AssemblyTitle("com.github.decibillyjoel.lc_giftbox_config")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/DecibillyJoel/LC_GiftBox_Config")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.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; } } } internal static class LCMPluginInfo { public const string PLUGIN_GUID = "com.github.decibillyjoel.lc_giftbox_config"; public const string PLUGIN_NAME = "LC_GiftBox_Config"; public const string PLUGIN_TS_TEAM = "DBJ"; public const string PLUGIN_VERSION = "1.1.1"; } namespace LC_GiftBox_Config { [BepInPlugin("com.github.decibillyjoel.lc_giftbox_config", "DBJ.LC_GiftBox_Config", "1.1.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public static ManualLogSource PluginLogger = null; public static ConfigEntry<bool> giftboxMechanicsDisabled = null; public static ConfigEntry<bool> giftboxDupeSoundsBugFixDisabled = null; public static ConfigEntry<bool> giftboxToolScrapValueBugfixDisabled = null; public static ConfigEntry<int> giftboxEggsplosionChance = null; public static ConfigEntry<int> spawnStoreItemChance = null; public static ConfigEntry<int> spawnScrapChance = null; public static ConfigEntry<int> spawnGiftBoxChance = null; public static ConfigEntry<int> spawnNothingChance = null; public static ConfigEntry<int> doNothingChance = null; public static ConfigEntry<int> scrapValueMin = null; public static ConfigEntry<int> scrapValueMax = null; public static ConfigEntry<int> scrapValueInfluence = null; public static ConfigEntry<int> scrapRarityMin = null; public static ConfigEntry<int> scrapRarityMax = null; public static ConfigEntry<int> scrapRarityInfluence = null; public static ConfigEntry<int> scrapValueIsGiftBoxChance = null; public static ConfigEntry<int> scrapValueAdditionChance = null; public static ConfigEntry<int> scrapValueAdditionMin = null; public static ConfigEntry<int> scrapValueAdditionMax = null; public static ConfigEntry<int> scrapValueMultiplierChance = null; public static ConfigEntry<int> scrapValueMultiplierMin = null; public static ConfigEntry<int> scrapValueMultiplierMax = null; public static ConfigEntry<int> giftboxValueAdditionChance = null; public static ConfigEntry<int> giftboxValueAdditionMin = null; public static ConfigEntry<int> giftboxValueAdditionMax = null; public static ConfigEntry<int> giftboxValueMultiplierChance = null; public static ConfigEntry<int> giftboxValueMultiplierMin = null; public static ConfigEntry<int> giftboxValueMultiplierMax = null; public static ConfigEntry<int> giftboxRarityAdditionChance = null; public static ConfigEntry<int> giftboxRarityAdditionMin = null; public static ConfigEntry<int> giftboxRarityAdditionMax = null; public static ConfigEntry<int> giftboxRarityMultiplierChance = null; public static ConfigEntry<int> giftboxRarityMultiplierMin = null; public static ConfigEntry<int> giftboxRarityMultiplierMax = null; public static ConfigEntry<int> giftboxSpawnChance = null; public static ConfigEntry<int> giftboxSpawnMin = null; public static ConfigEntry<int> giftboxSpawnMax = null; public static ConfigEntry<int> storeItemPriceMin = null; public static ConfigEntry<int> storeItemPriceMax = null; public static ConfigEntry<int> storeItemPriceInfluence = null; internal static readonly Harmony harmony = new Harmony("DBJ.LC_GiftBox_Config"); public static void Log(LogLevel logLevel, string logMessage) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) PluginLogger.Log(logLevel, (object)(logMessage ?? "")); } public static void Log(string logMessage) { Log((LogLevel)16, logMessage); } private void ValidateMinMaxOrder(ConfigEntry<int> minEntry, ConfigEntry<int> maxEntry) { if (minEntry.Value > maxEntry.Value) { Log((LogLevel)4, "|" + ((ConfigEntryBase)minEntry).Definition.Key + "| is greater than |" + ((ConfigEntryBase)maxEntry).Definition.Key + "! Swapping values..."); int value = maxEntry.Value; int value2 = minEntry.Value; minEntry.Value = value; maxEntry.Value = value2; } } private void ValidateConfigAndApplyPatches() { Log((LogLevel)32, "Validating config..."); ((BaseUnityPlugin)this).Config.SettingChanged -= ScheduleValidateConfigAndApplyPatches; if (spawnStoreItemChance.Value == 0 && spawnScrapChance.Value == 0 && spawnGiftBoxChance.Value == 0 && spawnNothingChance.Value == 0 && doNothingChance.Value == 0) { int maxValue = (((ConfigEntryBase)doNothingChance).Description.AcceptableValues as AcceptableValueRange<int>).MaxValue; Log((LogLevel)2, $"All [{((ConfigEntryBase)doNothingChance).Definition.Section}] config weights are 0! Setting |{((ConfigEntryBase)doNothingChance).Definition.Key}| to {maxValue}..."); doNothingChance.Value = maxValue; } ValidateMinMaxOrder(scrapValueMin, scrapValueMax); ValidateMinMaxOrder(scrapRarityMin, scrapRarityMax); ValidateMinMaxOrder(scrapValueAdditionMin, scrapValueAdditionMax); ValidateMinMaxOrder(scrapValueMultiplierMin, scrapValueMultiplierMax); ValidateMinMaxOrder(storeItemPriceMin, storeItemPriceMax); ValidateMinMaxOrder(giftboxRarityAdditionMin, giftboxRarityAdditionMax); ValidateMinMaxOrder(giftboxRarityMultiplierMin, giftboxRarityMultiplierMax); ValidateMinMaxOrder(giftboxValueAdditionMin, giftboxValueAdditionMax); ValidateMinMaxOrder(giftboxValueMultiplierMin, giftboxValueMultiplierMax); ValidateMinMaxOrder(giftboxSpawnMin, giftboxSpawnMax); ((BaseUnityPlugin)this).Config.SettingChanged += ScheduleValidateConfigAndApplyPatches; Log((LogLevel)32, "Unpatching..."); harmony.UnpatchSelf(); Log((LogLevel)32, "Patching..."); harmony.PatchAll(); Log((LogLevel)32, "Finished config validation and patching!"); } private void ScheduleValidateConfigAndApplyPatches(object? eventSender = null, SettingChangedEventArgs? eventArgs = null) { Log((LogLevel)32, "Scheduling config validation..."); string text = "ValidateConfigAndApplyPatches"; ((MonoBehaviour)this).CancelInvoke(text); ((MonoBehaviour)this).Invoke(text, 0.33f); } private void Awake() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Expected O, but got Unknown //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Expected O, but got Unknown //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Expected O, but got Unknown //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Expected O, but got Unknown //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Expected O, but got Unknown //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Expected O, but got Unknown //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Expected O, but got Unknown //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Expected O, but got Unknown //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Expected O, but got Unknown //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Expected O, but got Unknown //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Expected O, but got Unknown //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Expected O, but got Unknown //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_0508: Expected O, but got Unknown //IL_0537: Unknown result type (might be due to invalid IL or missing references) //IL_0541: Expected O, but got Unknown //IL_0577: Unknown result type (might be due to invalid IL or missing references) //IL_0581: Expected O, but got Unknown //IL_05b7: Unknown result type (might be due to invalid IL or missing references) //IL_05c1: Expected O, but got Unknown //IL_05f0: Unknown result type (might be due to invalid IL or missing references) //IL_05fa: Expected O, but got Unknown //IL_062c: Unknown result type (might be due to invalid IL or missing references) //IL_0636: Expected O, but got Unknown //IL_066b: Unknown result type (might be due to invalid IL or missing references) //IL_0675: Expected O, but got Unknown //IL_06a4: Unknown result type (might be due to invalid IL or missing references) //IL_06ae: Expected O, but got Unknown //IL_06e4: Unknown result type (might be due to invalid IL or missing references) //IL_06ee: Expected O, but got Unknown //IL_0724: Unknown result type (might be due to invalid IL or missing references) //IL_072e: Expected O, but got Unknown //IL_075d: Unknown result type (might be due to invalid IL or missing references) //IL_0767: Expected O, but got Unknown //IL_0799: Unknown result type (might be due to invalid IL or missing references) //IL_07a3: Expected O, but got Unknown //IL_07d8: Unknown result type (might be due to invalid IL or missing references) //IL_07e2: Expected O, but got Unknown //IL_0811: Unknown result type (might be due to invalid IL or missing references) //IL_081b: Expected O, but got Unknown //IL_0849: Unknown result type (might be due to invalid IL or missing references) //IL_0853: Expected O, but got Unknown //IL_0881: Unknown result type (might be due to invalid IL or missing references) //IL_088b: Expected O, but got Unknown //IL_08ba: Unknown result type (might be due to invalid IL or missing references) //IL_08c4: Expected O, but got Unknown //IL_08eb: Unknown result type (might be due to invalid IL or missing references) //IL_08f5: Expected O, but got Unknown //IL_091c: Unknown result type (might be due to invalid IL or missing references) //IL_0926: Expected O, but got Unknown //IL_094d: Unknown result type (might be due to invalid IL or missing references) //IL_0957: Expected O, but got Unknown PluginLogger = ((BaseUnityPlugin)this).Logger; Log("[v1.1.1] Loading..."); spawnStoreItemChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Item Type", "Store Item Chance (Selection Weight)", 50, new ConfigDescription("The selection weight of a gift box containing a store item. \n0 = will not happen \nLarger selection weight = more likely to happen \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); spawnScrapChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Item Type", "Scrap Item Chance (Selection Weight)", 30, new ConfigDescription("The selection weight of a gift box containing a scrap item. \n0 = will not happen \nLarger selection weight = more likely to happen \n \n[Vanilla Value: 100]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); spawnGiftBoxChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Item Type", "Gift Box Chance (Selection Weight)", 5, new ConfigDescription("The selection weight of a gift box containing another gift box. \n0 = will not happen \nLarger selection weight = more likely to happen \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); spawnNothingChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Item Type", "Empty Chance (Selection Weight)", 15, new ConfigDescription("The selection weight of a gift box being empty. \n0 = will not happen \nLarger selection weight = more likely to happen \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); doNothingChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Item Type", "Unmodified Chance (Selection Weight)", 0, new ConfigDescription("The selection weight of a gift box not being modified by this mod, i.e. so another gift box mod's effects can function instead. \n0 = will not happen \nLarger selection weight = more likely to happen \n \nIf you do not have any other gift box mods that function by transpiling OpenGiftBoxServerRpc(), I recommend leaving this value at 0. Otherwise, I recommend setting their probability values to 100% and this probability value to the weight you'd like to assign to the other mod, so that whenever this mod selects this hands-off behavior, the other mod's functionality will have a 100% chance to occur rather than simply using vanilla behavior", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); scrapValueMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Item", "Scrap Value Minimum", 0, new ConfigDescription("The minimum value required for a scrap item to be selected by the gift box \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>()))); scrapValueMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Item", "Scrap Value Maximum", int.MaxValue, new ConfigDescription("The maximum value required for a scrap item to be selected by the gift box \n \n[Vanilla Value: infinity]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>()))); scrapValueInfluence = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Item", "Scrap Value Influence (%)", -50, new ConfigDescription("How much influence a scrap item's value has over its selection weight. \n0 = scrap item's value does not influence its selection weight \nLarger influence percentage = high-value scrap items are more likely than low-value scrap items \nNegative influence percentage = high-value scrap items are less likely than low-value scrap items \n \nEach selectable scrap item is given a selection weight equal to their scrap value raised to the power of this percentage (i.e. 100% = 100 / 10 \n0 = 1, so the exponent is 1). e.g. if this percentage is set to 200%, a scrap item with a value of 2 has a selection weight of 4 (2 ^ 200% = 2 ^ 2 = 4), which is four times the selection weight of a scrap item with a value of 1 and therefore a selection weight of 1 (1 ^ 200% = 1 ^ 2 = 1). If this value is negative, then the selection weights are inverted - e.g. -100% results in a scrap item with a value of 2 receiving a selection weight of 0.5 (2 ^ -100% = 2 ^ -1 = 1 / (2 ^ 1) = 1 / 2 = 0.5) \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); scrapRarityMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Item", "Spawn Weight Minimum", 0, new ConfigDescription("The minimum spawn weight required for a scrap item to be selected by the gift box \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>()))); scrapRarityMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Item", "Spawn Weight Maximum", int.MaxValue, new ConfigDescription("The maximum value required for a scrap item to be selected by the gift box \n \n[Vanilla Value: infinity]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>()))); scrapRarityInfluence = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Item", "Spawn Weight Influence (%)", 50, new ConfigDescription("How much influence a scrap item's spawn weight within the current level has over its selection weight. \n0 = scrap item's spawn weight does not influence its selection weight \nLarger influence percentage = common scrap items are more likely than rare scrap items \nNegative influence percentage = common scrap items are less likely than rare scrap items \n \nEach selectable scrap item is given a selection weight equal to their spawn weight raised to the power of this percentage (i.e. 100% = 100 / 10 \n0 = 1, so the exponent is 1). e.g. if this percentage is set to 200%, a scrap item with a spawn weight of 2 has a selection weight of 4 (2 ^ 200% = 2 ^ 2 = 4), which is four times the selection weight of a scrap item with a spawn weight of 1 and therefore a selection weight of 1 (1 ^ 200% = 1 ^ 2 = 1). If this value is negative, then the selection weights are inverted - e.g. -100% results in a scrap item with a spawn weight of 2 receiving a selection weight of 0.5 (2 ^ -100% = 2 ^ -1 = 1 / (2 ^ 1) = 1 / 2 = 0.5) \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); storeItemPriceMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Store Item", "Price Minimum", 0, new ConfigDescription("The minimum store item price required for an item to be selected by the gift box \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>()))); storeItemPriceMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Store Item", "Price Maximum", int.MaxValue, new ConfigDescription("The maximum store item price required for an item to be selected by the gift box \n \n[Vanilla Value: infinity]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>()))); storeItemPriceInfluence = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Store Item", "Price Influence (%)", -100, new ConfigDescription("How much influence a store item's price has over its selection weight. \n0 = store item's price does not influence its selection weight \nLarger influence percentage = expensive store items are more likely than cheap store items \nNegative influence percentage = expensive store items are less likely than cheap store items \n \nEach selectable store item is given a selection weight equal to their store price raised to the power of this percentage (i.e. 100% = 100 / 10 \n0 = 1, so the exponent is 1). e.g. if this percentage is set to 200%, a store item with a price of 2 has a selection weight of 4 (2 ^ 200% = 2 ^ 2 = 4), which is four times the selection weight of a store item with a price of 1 and therefore a selection weight of 1 (1 ^ 200% = 1 ^ 2 = 1). If this value is negative, then the selection weights are inverted - e.g. -100% results in a store item with a price of 2 receiving a selection weight of 0.5 (2 ^ -100% = 2 ^ -1 = 1 / (2 ^ 1) = 1 / 2 = 0.5) \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); scrapValueIsGiftBoxChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Value", "Inherit Gift Box Value Chance (%)", 15, new ConfigDescription("The likelihood (% chance) of the selected scrap item having the same scrap value as the gift box itself \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); scrapValueAdditionChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Value", "Addition Chance (%)", 100, new ConfigDescription("The likelihood (% chance) of the selected scrap item receiving an addition to its scrap value (if the scrap item inherits the gift box's scrap value, this addition will not be applied) \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); scrapValueAdditionMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Value", "Addition Minimum", 30, new ConfigDescription("The minimum possible value of the addition applied to the selected scrap item's scrap value \n \n[Vanilla Value: 25]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); scrapValueAdditionMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Value", "Addition Maximum", 40, new ConfigDescription("The maximum possible value of the addition applied to the selected scrap item's scrap value \n \n[Vanilla Value: 35]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); scrapValueMultiplierChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Value", "Multiplier Chance (%)", 35, new ConfigDescription("The likelihood (% chance) of the selected scrap item receiving a multiplier to its scrap value (if the scrap item inherits the gift box's scrap value, this multiplier will not be applied) \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); scrapValueMultiplierMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Value", "Multiplier Minimum (%)", 120, new ConfigDescription("The minimum possible value of the multiplier applied to the selected scrap item's scrap value \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); scrapValueMultiplierMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Contained Scrap Value", "Multiplier Maximum (%)", 150, new ConfigDescription("The maximum possible value of the multiplier applied to the selected scrap item's scrap value \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); giftboxValueAdditionChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Scrap Value", "Addition Chance (%)", 100, new ConfigDescription("The likelihood (% chance) of the gift box receiving an addition to its scrap value \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxValueAdditionMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Scrap Value", "Addition Minimum", 30, new ConfigDescription("The minimum possible value of the addition applied to the gift box's scrap value \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); giftboxValueAdditionMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Scrap Value", "Addition Maximum", 40, new ConfigDescription("The maximum possible value of the addition applied to the gift box's scrap value \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); giftboxValueMultiplierChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Scrap Value", "Multiplier Chance (%)", 35, new ConfigDescription("The likelihood (% chance) of the gift box receiving a multiplier to its scrap value \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxValueMultiplierMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Scrap Value", "Multiplier Minimum (%)", 120, new ConfigDescription("The minimum possible value of the multiplier applied to the gift box's scrap value \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); giftboxValueMultiplierMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Scrap Value", "Multiplier Maximum (%)", 150, new ConfigDescription("The maximum possible value of the multiplier applied to the gift box's scrap value \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); giftboxRarityAdditionChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Weight", "Addition Chance (%)", 25, new ConfigDescription("The likelihood (% chance) of gift boxes receiving an addition to their spawn weight within the current level \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxRarityAdditionMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Weight", "Addition Minimum", 10, new ConfigDescription("The minimum possible value of the addition applied to gift boxes' spawn weight within the current level \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); giftboxRarityAdditionMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Weight", "Addition Maximum", 15, new ConfigDescription("The maximum possible value of the addition applied to gift boxes' spawn weight within the current level \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1000, 1000), Array.Empty<object>()))); giftboxRarityMultiplierChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Weight", "Multiplier Chance (%)", 25, new ConfigDescription("The likelihood (% chance) of gift boxes receiving a multiplier to their spawn weight within the current level \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxRarityMultiplierMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Weight", "Multiplier Minimum", 120, new ConfigDescription("The minimum possible value of the multiplier applied to gift boxes' spawn weight within the current level \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); giftboxRarityMultiplierMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Weight", "Multiplier Maximum", 150, new ConfigDescription("The maximum possible value of the multiplier applied to gift boxes' spawn weight within the current level \n \n[Vanilla Value: 100%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()))); giftboxSpawnChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Anomaly", "Anomalous Spawning Chance (%)", 65, new ConfigDescription("The likelihood (% chance) of gift boxes anomalously spawning in the current level, separate from the level's natural scrap pool mechanics \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxSpawnMin = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Anomaly", "Minimum Gift Boxes", 2, new ConfigDescription("The minimum possible number of gift boxes to be anomalously spawned \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxSpawnMax = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Spawn Anomaly", "Maximum Gift Boxes", 5, new ConfigDescription("The maximum possible number of gift boxes to be anomalously spawned \n \n[Vanilla Value: 0]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxEggsplosionChance = LethalConfigNicerizer.Nicerize<int>(((BaseUnityPlugin)this).Config.Bind<int>("Gift Box Behaviors", "Empty Gift Box Eggsplosion Chance (%)", 100, new ConfigDescription("The likelihood (% chance) of an empty gift box non-harmfully eggsploding (it won't harm you, but it may attract enemies who will) \n \n[Vanilla Value: 0%]", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()))); giftboxMechanicsDisabled = LethalConfigNicerizer.Nicerize<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility / Debugging", "Disable All Mod Mechanics", false, new ConfigDescription("WARNING: May cause unexpected game behaviors, desyncs, or loss / corruption of mod-related save data! Do not use this setting unless you know what you're doing! \n \nToggle this setting to disable the modded gift box mechanics", (AcceptableValueBase)null, Array.Empty<object>()))); giftboxDupeSoundsBugFixDisabled = LethalConfigNicerizer.Nicerize<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility / Debugging", "Disable Gift Box Duplicate Sounds Bugfix", false, new ConfigDescription("Toggle this setting to disable the gift box duplicate sounds bugfix", (AcceptableValueBase)null, Array.Empty<object>()))); giftboxToolScrapValueBugfixDisabled = LethalConfigNicerizer.Nicerize<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility / Debugging", "Disable Gift Box Setting Tool Scrap Value Bugfix", false, new ConfigDescription("Toggle this setting to disable the bugfix for the gift box setting a tool's scrap value", (AcceptableValueBase)null, Array.Empty<object>()))); MigrateOldEntries(("Gift Box - Gift Box Value", "Chance for the gift box to receive scrap value addition (%)", (ConfigEntryBase)(object)giftboxValueAdditionChance), ("Gift Box - Gift Box Value", "Minimum gift box value addition", (ConfigEntryBase)(object)giftboxValueAdditionMin), ("Gift Box - Gift Box Value", "Maximum gift box value addition", (ConfigEntryBase)(object)giftboxValueAdditionMax), ("Gift Box - Gift Box Value", "Chance for gift box to receive scrap value multiplier (%)", (ConfigEntryBase)(object)giftboxValueMultiplierChance), ("Gift Box - Gift Box Value", "Minimum gift box value multiplier (%)", (ConfigEntryBase)(object)giftboxValueMultiplierMin), ("Gift Box - Gift Box Value", "Maximum gift box value multiplier (%)", (ConfigEntryBase)(object)giftboxValueMultiplierMax), ("Gift Box - Gift Box Natural Spawn Chance", "Chance for gift boxes to receive spawn weight addition (%)", (ConfigEntryBase)(object)giftboxRarityAdditionChance), ("Gift Box - Gift Box Natural Spawn Chance", "Minimum gift box spawn weight addition", (ConfigEntryBase)(object)giftboxRarityAdditionMin), ("Gift Box - Gift Box Natural Spawn Chance", "Maximum gift box spawn weight addition", (ConfigEntryBase)(object)giftboxRarityAdditionMax), ("Gift Box - Gift Box Natural Spawn Chance", "Chance for gift boxes to receive spawn weight multiplier (%)", (ConfigEntryBase)(object)giftboxRarityMultiplierChance), ("Gift Box - Gift Box Natural Spawn Chance", "Minimum gift box spawn weight multiplier (%)", (ConfigEntryBase)(object)giftboxRarityMultiplierMin), ("Gift Box - Gift Box Natural Spawn Chance", "Maximum gift box spawn weight multiplier (%)", (ConfigEntryBase)(object)giftboxRarityMultiplierMax), ("Gift Box - Gift Box Anomalous Spawning", "Chance for gift boxes to anomalously spawn (%)", (ConfigEntryBase)(object)giftboxSpawnChance), ("Gift Box - Gift Box Anomalous Spawning", "Minimum number of anomalously spawned gift boxes", (ConfigEntryBase)(object)giftboxSpawnMin), ("Gift Box - Gift Box Anomalous Spawning", "Maximum number of anomalously spawned gift boxes", (ConfigEntryBase)(object)giftboxSpawnMax), ("Gift Box - Behavior Selection", "Chance to select a store item (Selection Weight)", (ConfigEntryBase)(object)spawnStoreItemChance), ("Gift Box - Behavior Selection", "Chance to select a scrap item (Selection Weight)", (ConfigEntryBase)(object)spawnScrapChance), ("Gift Box - Behavior Selection", "Chance to select another gift box (Selection Weight)", (ConfigEntryBase)(object)spawnGiftBoxChance), ("Gift Box - Behavior Selection", "Chance to select no item (Selection Weight)", (ConfigEntryBase)(object)spawnNothingChance), ("Gift Box - Behavior Selection", "Chance to leave gift box unmodified (Selection Weight)", (ConfigEntryBase)(object)doNothingChance), ("Gift Box - Scrap Selection", "Minimum selectable scrap value", (ConfigEntryBase)(object)scrapValueMin), ("Gift Box - Scrap Selection", "Maximum selectable scrap value", (ConfigEntryBase)(object)scrapValueMax), ("Gift Box - Scrap Selection", "Scrap value influence percentage (%)", (ConfigEntryBase)(object)scrapValueInfluence), ("Gift Box - Scrap Selection", "Minimum selectable scrap spawn weight", (ConfigEntryBase)(object)scrapRarityMin), ("Gift Box - Scrap Selection", "Maximum selectable scrap spawn weight", (ConfigEntryBase)(object)scrapRarityMax), ("Gift Box - Scrap Selection", "Scrap spawn weight influence percentage (%)", (ConfigEntryBase)(object)scrapRarityInfluence), ("Gift Box - Scrap Item Value", "Chance for scrap item to inherit gift box value (%)", (ConfigEntryBase)(object)scrapValueIsGiftBoxChance), ("Gift Box - Scrap Item Value", "Chance for scrap item to receive scrap value addition (%)", (ConfigEntryBase)(object)scrapValueAdditionChance), ("Gift Box - Scrap Item Value", "Minimum scrap item value addition", (ConfigEntryBase)(object)scrapValueAdditionMin), ("Gift Box - Scrap Item Value", "Maximum scrap item value addition", (ConfigEntryBase)(object)scrapValueAdditionMax), ("Gift Box - Scrap Item Value", "Chance for scrap item to receive scrap value multiplier (%)", (ConfigEntryBase)(object)scrapValueMultiplierChance), ("Gift Box - Scrap Item Value", "Minimum scrap item value multiplier (%)", (ConfigEntryBase)(object)scrapValueMultiplierMin), ("Gift Box - Scrap Item Value", "Maximum scrap item value multiplier (%)", (ConfigEntryBase)(object)scrapValueMultiplierMax), ("Gift Box - Store Item Selection", "Minimum selectable store item price", (ConfigEntryBase)(object)storeItemPriceMin), ("Gift Box - Store Item Selection", "Maximum selectable store item price", (ConfigEntryBase)(object)storeItemPriceMax), ("Gift Box - Store Item Selection", "Store item price influence percentage (%)", (ConfigEntryBase)(object)storeItemPriceInfluence), ("Gift Box Behaviors", "Disable All Mod Mechanics", (ConfigEntryBase)(object)giftboxMechanicsDisabled), ("Gift Box Behaviors", "Disable Gift Box Duplicate Sounds Bugfix", (ConfigEntryBase)(object)giftboxDupeSoundsBugFixDisabled), ("Gift Box Behaviors", "Disable Gift Box Setting Tool Scrap Value Bugfix", (ConfigEntryBase)(object)giftboxToolScrapValueBugfixDisabled)); ValidateConfigAndApplyPatches(); Log("[v1.1.1] Finished loading!"); } private void MigrateOldEntries(params (string oldSection, string oldKey, ConfigEntryBase newEntry)[] migrations) { Dictionary<ConfigDefinition, string> orphanedEntries = (Dictionary<ConfigDefinition, string>)(AccessTools.DeclaredPropertyGetter(typeof(ConfigFile), "OrphanedEntries")?.Invoke(((BaseUnityPlugin)this).Config, Array.Empty<object>())); if (orphanedEntries == null) { Log((LogLevel)4, "Unable to retrieve orphaned entries!"); return; } int migrationsPerformed = 0; CollectionExtensions.Do<(string, string, ConfigEntryBase)>((IEnumerable<(string, string, ConfigEntryBase)>)migrations, (Action<(string, string, ConfigEntryBase)>)delegate((string oldSection, string oldKey, ConfigEntryBase newEntry) migration) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition(migration.oldSection, migration.oldKey); if (orphanedEntries.TryGetValue(val, out string value)) { migration.newEntry.SetSerializedValue(value); migrationsPerformed++; Log($"[{migrationsPerformed} Migrated [{val.Section}].[{val.Key}] to [{migration.newEntry.Definition.Section}].[{migration.newEntry.Definition.Key}]"); orphanedEntries.Remove(val); } }); if (migrationsPerformed != 0) { Log($"Successfully migrated {migrationsPerformed} orphan entries! Saving to file..."); ((BaseUnityPlugin)this).Config.Save(); Log("Migrations saved to file!"); } } } } namespace LC_GiftBox_Config.Patches.GiftBoxItemPatches { [StaticNetcode] [HarmonyPatch(typeof(GiftBoxItem))] public static class GiftBoxItemPatch { public class GiftBoxModdedParams { [ES3Serializable] public bool CanEggsplode; [ES3Serializable] public bool ScrapHasGiftBoxValue; [ES3Serializable] public int ScrapValue; [ES3Serializable] public int NestedScrapId = -1; } public class GiftBoxModdedBehavior : MonoBehaviour { public GiftBoxModdedParams Params; public GiftBoxModdedBehavior() { Params = new GiftBoxModdedParams(); } public GiftBoxModdedBehavior(GiftBoxModdedParams _Params) { Params = _Params; } public static implicit operator GiftBoxModdedParams?(GiftBoxModdedBehavior? component) { return component?.Params; } } public const int GIFTBOX_ITEM_ID = 152767; public static Item? _GIFTBOX_ITEM = null; public static GameObject? _EGGSPLOSION = null; public static AudioClip? _EGGPOP = null; public static List<int> giftboxBehaviors = new List<int>(5) { 0, 0, 0, 0, 0 }; public const int DO_NOTHING = 0; public const int SPAWN_STORE_ITEM = 1; public const int SPAWN_SCRAP = 2; public const int SPAWN_GIFTBOX = 3; public const int SPAWN_NOTHING = 4; public static GiftBoxModdedParams? parentGiftboxParams = null; public static Terminal? _terminal = null; public static Item[] _terminalBuyableItemsList = Array.Empty<Item>(); public static List<Item> _filteredStoreItems = new List<Item>(); public static List<double> _filteredStoreItemWeights = new List<double>(); public static List<SpawnableItemWithRarity> _currentLevelSpawnableScrap = new List<SpawnableItemWithRarity>(); public static List<SpawnableItemWithRarity> _filteredScrapItems = new List<SpawnableItemWithRarity>(); public static List<double> _filteredScrapItemWeights = new List<double>(); public static Item GIFTBOX_ITEM => _GIFTBOX_ITEM ?? (_GIFTBOX_ITEM = StartOfRound.Instance.allItemsList.itemsList.ToList().First((Item item) => item.itemId == 152767)); public static GameObject EGGSPLOSION => _EGGSPLOSION ?? (_EGGSPLOSION = Resources.FindObjectsOfTypeAll<GameObject>().First((GameObject obj) => ((Object)obj).name == "EasterEggExplosionParticle")); public static AudioClip? EGGPOP => _EGGPOP ?? (_EGGPOP = Resources.FindObjectsOfTypeAll<AudioClip>().First((AudioClip clip) => ((Object)clip).name == "EasterEggPop")); public static List<Item> filteredStoreItems { get { if ((Object)(object)_terminal == (Object)null || !((Behaviour)_terminal).isActiveAndEnabled) { _terminal = Object.FindAnyObjectByType<Terminal>(); _terminalBuyableItemsList = Array.Empty<Item>(); } if (_terminalBuyableItemsList != _terminal?.buyableItemsList) { _terminalBuyableItemsList = _terminal?.buyableItemsList ?? Array.Empty<Item>(); _filteredStoreItems.Clear(); } if (_filteredStoreItems.Count == 0) { _filteredStoreItems = _terminalBuyableItemsList.Where((Item item) => item.creditsWorth >= Plugin.storeItemPriceMin.Value && item.creditsWorth <= Plugin.storeItemPriceMax.Value).ToList(); } return _filteredStoreItems; } set { if (value == null) { _filteredStoreItems.Clear(); } else { _filteredStoreItems = value; } } } public static List<double> filteredStoreItemWeights { get { _ = filteredStoreItems; if (_filteredStoreItemWeights.Count == 0) { _filteredStoreItemWeights = _filteredStoreItems.Select((Item item) => Math.Pow(item.creditsWorth, (double)Plugin.scrapValueInfluence.Value / 100.0)).ToList(); } return _filteredStoreItemWeights; } set { if (value == null) { _filteredStoreItemWeights.Clear(); } else { _filteredStoreItemWeights = value; } } } public static List<SpawnableItemWithRarity> filteredScrapItems { get { if (_currentLevelSpawnableScrap != RoundManager.Instance.currentLevel.spawnableScrap) { _currentLevelSpawnableScrap = RoundManager.Instance.currentLevel.spawnableScrap; _filteredScrapItems.Clear(); _filteredScrapItemWeights.Clear(); } if (_filteredScrapItems.Count == 0) { _filteredScrapItems = _currentLevelSpawnableScrap.Where((SpawnableItemWithRarity item) => item.spawnableItem.itemId != 152767 && item.spawnableItem.minValue >= Plugin.scrapValueMin.Value && item.spawnableItem.maxValue <= Plugin.scrapValueMax.Value && item.rarity >= Plugin.scrapRarityMin.Value && item.rarity <= Plugin.scrapRarityMax.Value).ToList(); } return _filteredScrapItems; } set { if (value == null) { _filteredScrapItems.Clear(); } else { _filteredScrapItems = value; } } } public static List<double> filteredScrapItemWeights { get { _ = filteredScrapItems; if (_filteredScrapItemWeights.Count == 0) { _filteredScrapItemWeights = _filteredScrapItems.Select((SpawnableItemWithRarity item) => Math.Pow((double)(item.spawnableItem.minValue + item.spawnableItem.maxValue) / 2.0, (double)Plugin.scrapValueInfluence.Value / 100.0) + Math.Pow(item.rarity, (double)Plugin.scrapRarityInfluence.Value / 100.0)).ToList(); } return _filteredScrapItemWeights; } set { if (value == null) { _filteredScrapItemWeights.Clear(); } else { _filteredScrapItemWeights = value; } } } [HarmonyPatch("GetItemDataToSave")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] internal static IEnumerable<CodeInstruction> GetItemDataToSave(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIndex(iLStepper.Instructions.Count); iLStepper.GotoIL((CodeInstruction code) => CodeInstructionExtensions.LoadsConstant(code, 0L), null, 0, reverse: true); iLStepper.OverwriteIL(CodeInstructionPolyfills.LoadConstant(int.MaxValue)); return iLStepper.Instructions; } public static bool OverrideLoadItemSaveData(GiftBoxItem giftbox, int saveData) { GiftBoxModdedParams giftBoxModdedParams = ((Component)giftbox).GetComponent<GiftBoxModdedBehavior>(); if (giftBoxModdedParams == null) { return false; } giftbox.objectInPresentItem = ((saveData == int.MaxValue) ? null : StartOfRound.Instance.allItemsList.itemsList.ElementAtOrDefault(saveData)); giftbox.objectInPresent = giftbox.objectInPresentItem?.spawnPrefab; giftbox.objectInPresentValue = giftBoxModdedParams.ScrapValue; giftbox.loadedItemFromSave = true; return true; } [HarmonyPatch("LoadItemSaveData")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> LoadItemSaveData(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.Calls(typeof(GrabbableObject), "LoadItemSaveData"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.Start] Call GrabbableObject.LoadItemSaveData() not found!"); iLStepper.GotoIndex(null, 1); Label label = iLStepper.DeclareLabel(); iLStepper.InsertIL(new List<CodeInstruction>(4) { CodeInstructionPolyfills.LoadArgument(0), CodeInstructionPolyfills.LoadArgument(1), CodeInstructionPolyfills.Call(typeof(GiftBoxItemPatch), "OverrideLoadItemSaveData"), new CodeInstruction(OpCodes.Brtrue, (object)label) }); iLStepper.GotoIL((CodeInstruction code) => code.StoresField(typeof(GiftBoxItem), "loadedItemFromSave"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.Start] Store field GrabbableObject.loadedItemFromSave not found!"); iLStepper.GotoIndex(null, 1); iLStepper.InsertIL(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Nop, (object)null), new Label[1] { label })); return iLStepper.Instructions; } public static bool InitGiftboxModdedBehavior(GiftBoxItem giftbox, Random giftboxBehaviorSeed, Random valueBehaviorSeed) { int randomWeightedIndex = Probability.GetRandomWeightedIndex(giftboxBehaviors, giftboxBehaviorSeed); if (randomWeightedIndex == 0) { return false; } GiftBoxModdedParams @params = ((Component)giftbox).gameObject.AddComponent<GiftBoxModdedBehavior>().Params; @params.CanEggsplode = giftboxBehaviorSeed.Next(0, 100) < Plugin.giftboxEggsplosionChance.Value; switch (randomWeightedIndex) { case 1: { int randomWeightedIndex3 = Probability.GetRandomWeightedIndex(filteredStoreItemWeights, giftboxBehaviorSeed); if (randomWeightedIndex3 != -1) { giftbox.objectInPresentItem = filteredStoreItems[randomWeightedIndex3]; giftbox.objectInPresent = giftbox.objectInPresentItem.spawnPrefab; } break; } case 3: giftbox.objectInPresentItem = ((GrabbableObject)giftbox).itemProperties; giftbox.objectInPresent = giftbox.objectInPresentItem.spawnPrefab; if (parentGiftboxParams != null) { @params.NestedScrapId = parentGiftboxParams.NestedScrapId; } else { int randomWeightedIndex2 = Probability.GetRandomWeightedIndex(filteredScrapItemWeights, giftboxBehaviorSeed); Item nestedScrapItem = filteredScrapItems.ElementAtOrDefault(randomWeightedIndex2)?.spawnableItem; if (Object.op_Implicit((Object)(object)nestedScrapItem)) { @params.NestedScrapId = StartOfRound.Instance.allItemsList.itemsList.FindIndex((Item item) => (Object)(object)item == (Object)(object)nestedScrapItem); } } goto case 2; case 2: if (randomWeightedIndex == 2) { int num = parentGiftboxParams?.NestedScrapId ?? Probability.GetRandomWeightedIndex(filteredScrapItemWeights, giftboxBehaviorSeed); if (num == -1) { break; } giftbox.objectInPresentItem = filteredScrapItems[num].spawnableItem; giftbox.objectInPresent = giftbox.objectInPresentItem.spawnPrefab; } giftbox.objectInPresentValue = valueBehaviorSeed.Next(giftbox.objectInPresentItem.minValue, giftbox.objectInPresentItem.maxValue); if (valueBehaviorSeed.Next(0, 100) < Plugin.scrapValueAdditionChance.Value) { giftbox.objectInPresentValue += valueBehaviorSeed.Next(Plugin.scrapValueAdditionMin.Value, Plugin.scrapValueAdditionMax.Value + 1); } if (valueBehaviorSeed.Next(0, 100) < Plugin.scrapValueMultiplierChance.Value) { giftbox.objectInPresentValue = (int)((double)giftbox.objectInPresentValue * ((double)Plugin.scrapValueMultiplierMin.Value + (double)(Plugin.scrapValueMultiplierMax.Value - Plugin.scrapValueMultiplierMin.Value) * valueBehaviorSeed.NextDouble()) / 100.0); } if (valueBehaviorSeed.Next(0, 100) < Plugin.scrapValueIsGiftBoxChance.Value) { @params.ScrapHasGiftBoxValue = true; } break; default: throw new Exception("[Patches.GiftBoxItemPatches.GiftBoxItemPatch.InitGiftboxModdedBehavior] Giftbox Behavior selection failed! This should never happen!"); case 4: break; } @params.ScrapValue = giftbox.objectInPresentValue; return true; } [HarmonyPatch("Start")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> Start(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } filteredStoreItems = null; filteredScrapItems = null; giftboxBehaviors[0] = Plugin.doNothingChance.Value; giftboxBehaviors[1] = Plugin.spawnStoreItemChance.Value; giftboxBehaviors[2] = Plugin.spawnScrapChance.Value; giftboxBehaviors[3] = Plugin.spawnGiftBoxChance.Value; giftboxBehaviors[4] = Plugin.spawnNothingChance.Value; ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.LoadsProperty(typeof(NetworkBehaviour), "IsServer"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.Start] Property NetworkBehaviour.IsServer not found!"); iLStepper.GotoIndex(null, 1); iLStepper.InsertIL(new List<CodeInstruction>(6) { CodeInstructionPolyfills.LoadArgument(0), CodeInstructionPolyfills.LoadLocal(0), CodeInstructionPolyfills.LoadLocal(1), CodeInstructionPolyfills.Call(typeof(GiftBoxItemPatch), "InitGiftboxModdedBehavior"), new CodeInstruction(OpCodes.Not, (object)null), new CodeInstruction(OpCodes.And, (object)null) }); return iLStepper.Instructions; } public static void NestedGiftboxFun(GiftBoxItem giftbox, GrabbableObject? spawnedObj) { //IL_0028: 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) if (!((Object)(object)spawnedObj == (Object)null) && spawnedObj.itemProperties.itemId == 152767) { ((Component)spawnedObj).transform.localScale = ((Component)giftbox).transform.localScale * 0.925f; ((Object)spawnedObj).name = "Nested " + ((Object)giftbox).name; ScanNodeProperties componentInChildren = ((Component)giftbox).GetComponentInChildren<ScanNodeProperties>(); ScanNodeProperties componentInChildren2 = ((Component)spawnedObj).GetComponentInChildren<ScanNodeProperties>(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.headerText = "Nested " + componentInChildren.headerText; } else { Plugin.Log((LogLevel)4, "Failed to prepare nested giftbox scan node :("); } GiftBoxModdedParams giftBoxModdedParams = ((Component)spawnedObj).GetComponent<GiftBoxModdedBehavior>(); } } public static bool OverrideOpenGiftBox(GiftBoxItem giftbox) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) GiftBoxModdedParams giftBoxModdedParams = ((Component)giftbox).GetComponent<GiftBoxModdedBehavior>(); if (giftBoxModdedParams == null) { return false; } if (giftBoxModdedParams.ScrapHasGiftBoxValue) { giftbox.objectInPresentValue = ((GrabbableObject)giftbox).scrapValue; } parentGiftboxParams = giftBoxModdedParams; GrabbableObject val = SpawnGiftItem(giftbox); parentGiftboxParams = null; NestedGiftboxFun(giftbox, val); if ((Object)(object)val == (Object)null && giftBoxModdedParams.CanEggsplode) { EggsplosionClientRpc(NetworkObjectReference.op_Implicit(((Component)giftbox).gameObject)); } return true; } [HarmonyPatch("OpenGiftBoxServerRpc")] [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] public static GrabbableObject? SpawnGiftItem(GiftBoxItem giftbox) { Transpiler(null, null, null); return null; static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Expected O, but got Unknown //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Expected O, but got Unknown ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.StoresLocal(0), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.SpawnGiftItem] Store Local 0 (gameObject) not found"); iLStepper.GotoIL(ILPatterns.NextEmptyStack(), null, 1, reverse: true, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.SpawnGiftItem] OpCodes.Ldnull not found"); iLStepper.RemoveIL(0, iLStepper.CurrentIndex, shiftCurrentIndex: true, pinLabels: false, pinBlocks: false); Func<CodeInstruction, bool> searchCondition = (CodeInstruction code) => code.LoadsString("Error: There is no object in gift box!"); int? num = null; iLStepper.GotoIL(searchCondition, num, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.SpawnGiftItem] \"no object\" error message not found"); num = 1 + iLStepper.FindIL(ILPatterns.NextEmptyStack(), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.SpawnGiftItem] Call Debug.LogError(object) not found"); iLStepper.RemoveIL(null, num); iLStepper.GotoIL((CodeInstruction code) => code.Calls(typeof(GrabbableObject), "SetScrapValue", new Type[1] { typeof(int) }), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.SpawnGiftItem] Call GrabbableObject.SetScrapValue(int) not found"); num = null; iLStepper.GotoIndex(num, 1); num = iLStepper.FindIL(ILPatterns.NextEmptyStack(), null, 0, reverse: true, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.SpawnGiftItem] 1st Load Local 4 (component) not found"); List<CodeInstruction> collection = iLStepper.RemoveIL(null, num, shiftCurrentIndex: true, pinLabels: false, pinBlocks: false); Label label = iLStepper.DeclareLabel(); List<CodeInstruction> list = new List<CodeInstruction>(); list.Add(CodeInstructionPolyfills.LoadLocal(4)); list.Add(CodeInstructionPolyfills.LoadField(typeof(GrabbableObject), "itemProperties")); list.Add(CodeInstructionPolyfills.LoadField(typeof(Item), "isScrap")); list.Add(new CodeInstruction(OpCodes.Brfalse, (object)label)); list.AddRange(collection); list.Add(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Nop, (object)null), new Label[1] { label })); List<CodeInstruction> list2 = iLStepper.InsertIL(list); iLStepper.GotoIL((CodeInstruction code) => code.Calls(typeof(GiftBoxItem), "OpenGiftBoxClientRpc"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.OpenGiftBoxServerRpc_DuplicateSoundsBugfix] Call GiftBoxItem.OpenGiftBoxClientRpc not found!"); iLStepper.GotoIndex(null, 1); iLStepper.InsertIL(new List<CodeInstruction>(2) { CodeInstructionPolyfills.LoadLocal(4), new CodeInstruction(OpCodes.Ret, (object)null) }, null, shiftCurrentIndex: true, pinLabels: false, pinBlocks: false); iLStepper.GotoIndex(iLStepper.Instructions.Count); iLStepper.GotoIL((CodeInstruction code) => code.opcode == OpCodes.Ret, null, 0, reverse: true, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.OpenGiftBoxServerRpc_DuplicateSoundsBugfix] Final return not found!"); iLStepper.InsertIL(CodeInstructionPolyfills.LoadNull()); return iLStepper.Instructions; } } [HarmonyPatch("OpenGiftBoxServerRpc")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> OpenGiftBoxServerRpc(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.StoresLocal(0), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.OpenGiftBoxServerRpc] Store Local 0 (gameObject) not found"); iLStepper.GotoIL(ILPatterns.NextEmptyStack(), null, 1, reverse: true, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.OpenGiftBoxServerRpc] Beginning of Store Local 0 (gameObject) not found"); Label label = iLStepper.DeclareLabel(); iLStepper.InsertIL(new List<CodeInstruction>(3) { CodeInstructionPolyfills.LoadArgument(0), CodeInstructionPolyfills.Call(typeof(GiftBoxItemPatch), "OverrideOpenGiftBox"), new CodeInstruction(OpCodes.Brtrue, (object)label) }); iLStepper.GotoIL((CodeInstruction code) => code.Calls(typeof(GiftBoxItem), "OpenGiftBoxNoPresentClientRpc"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.OpenGiftBoxServerRpc] Call GiftBoxItem.OpenGiftBoxNoPresentClientRpc not found!"); iLStepper.GotoIndex(null, 1); iLStepper.InsertIL(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Nop, (object)null), new Label[1] { label })); return iLStepper.Instructions; } [ClientRpc] public static void EggsplosionClientRpc(NetworkObjectReference giftboxNGO) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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) GameObject obj = NetworkObjectReference.op_Implicit(giftboxNGO); GiftBoxItem val = ((obj != null) ? obj.GetComponent<GiftBoxItem>() : null); if (!((Object)(object)val == (Object)null)) { if ((Object)(object)EGGSPLOSION != (Object)null) { Transform val2 = (((GrabbableObject)val).isInElevator ? StartOfRound.Instance.elevatorTransform : RoundManager.Instance.mapPropsContainer.transform); Object.Instantiate<GameObject>(EGGSPLOSION, ((Component)val).transform.position, Quaternion.identity, val2); } else { Plugin.Log((LogLevel)4, "EGGSPLOSION VFX not found!"); } if ((Object)(object)EGGPOP != (Object)null) { val.presentAudio.PlayOneShot(EGGPOP, 0.67f); WalkieTalkie.TransmitOneShotAudio(val.presentAudio, EGGPOP, 0.67f); RoundManager.Instance.PlayAudibleNoise(((Component)val.presentAudio).transform.position, 15f, 0.67f, 1, ((GrabbableObject)val).isInShipRoom && StartOfRound.Instance.hangarDoorsClosed, 0); } else { Plugin.Log((LogLevel)4, "EGGSPLOSION SFX not found!"); } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> waitForGiftPresentToSpawnOnClient(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.StoresField(typeof(GrabbableObject), "reachedFloorTarget"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.waitForGiftPresentToSpawnOnClient] Store Field GrabbableObject.reachedFloorTarget not found"); iLStepper.GotoIndex(null, 1); iLStepper.InsertIL(new List<CodeInstruction>(3) { CodeInstructionPolyfills.LoadLocal(1), CodeInstructionPolyfills.LoadLocal(2), CodeInstructionPolyfills.Call(typeof(GiftBoxItemPatch), "NestedGiftboxFun") }); return iLStepper.Instructions; } [HarmonyPatch("OpenGiftBoxServerRpc")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> OpenGiftBoxServerRpc_DuplicateSoundsBugfix(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown if (Plugin.giftboxDupeSoundsBugFixDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.Calls(typeof(GiftBoxItem), "OpenGiftBoxClientRpc"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.OpenGiftBoxServerRpc_DuplicateSoundsBugfix] Call GiftBoxItem.OpenGiftBoxClientRpc not found!"); iLStepper.GotoIndex(null, 1); Label label = iLStepper.DeclareLabel(); iLStepper.InsertIL(new CodeInstruction(OpCodes.Br, (object)label), null, shiftCurrentIndex: true, pinLabels: false, pinBlocks: false); iLStepper.GotoIL((CodeInstruction code) => code.Calls(typeof(GiftBoxItem), "OpenGiftBoxNoPresentClientRpc"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.OpenGiftBoxServerRpc_DuplicateSoundsBugfix] Call GiftBoxItem.OpenGiftBoxNoPresentClientRpc not found!"); iLStepper.GotoIndex(null, 1); iLStepper.InsertIL(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Nop, (object)null), new Label[1] { label })); return iLStepper.Instructions; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> waitForGiftPresentToSpawnOnClient_ToolBugfix(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown if (Plugin.giftboxToolScrapValueBugfixDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.StoresField(typeof(RoundManager), "totalScrapValueInLevel"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.waitForGiftPresentToSpawnOnClient_ToolBugfix] Store Field RoundManager.totalScrapValueInLevel not found"); int? num = null; iLStepper.GotoIndex(num, 1); Label label = iLStepper.DeclareLabel(); List<CodeInstruction> list = new List<CodeInstruction> { CodeInstructionPolyfills.LoadLocal(2), CodeInstructionPolyfills.LoadField(typeof(GrabbableObject), "itemProperties"), CodeInstructionPolyfills.LoadField(typeof(Item), "isScrap"), new CodeInstruction(OpCodes.Brfalse, (object)label) }; num = 1 + iLStepper.FindIL((CodeInstruction code) => code.Calls(typeof(GrabbableObject), "SetScrapValue"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.GiftBoxItemPatch.waitForGiftPresentToSpawnOnClient_ToolBugfix] Call GrabbableObject.SetScrapValue not found"); list.AddRange(iLStepper.RemoveIL(null, num, shiftCurrentIndex: true, pinLabels: false, pinBlocks: false)); list.Add(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Nop, (object)null), new Label[1] { label })); iLStepper.InsertIL(list); return iLStepper.Instructions; } } [HarmonyPatch(typeof(RoundManager))] internal static class RoundManagerPatch { internal static void AnomalouslySpawnGiftBoxes(RoundManager roundmanager, List<Item> ScrapToSpawn, int spawnOneItemIndex, List<SpawnableItemWithRarity> spawnableScrap) { if (spawnOneItemIndex == -1 || spawnableScrap[spawnOneItemIndex].spawnableItem.itemId == 152767) { Random anomalyRandom = roundmanager.AnomalyRandom; if (anomalyRandom.Next(0, 100) < Plugin.giftboxSpawnChance.Value) { int count = anomalyRandom.Next(Plugin.giftboxSpawnMin.Value, Plugin.giftboxSpawnMax.Value + 1); ScrapToSpawn.AddRange(Enumerable.Repeat<Item>(GiftBoxItemPatch.GIFTBOX_ITEM, count).ToList()); } } } internal static void AdjustGiftBoxSpawnWeight(RoundManager roundmanager, int[] weights, List<SpawnableItemWithRarity> spawnableScrap) { Random anomalyRandom = roundmanager.AnomalyRandom; if (weights.Length != spawnableScrap.Count) { Plugin.Log((LogLevel)2, "[LC_GiftBox_Config.Patches.RoundManagerPatch.AdjustGiftBoxSpawnWeight] weights length does not match spawnableScrap length! Wonkiness may occur!"); } for (int i = 0; i < Math.Min(spawnableScrap.Count, weights.Length); i++) { if (spawnableScrap[i].spawnableItem.itemId == 152767) { if (anomalyRandom.Next(0, 100) < Plugin.giftboxRarityAdditionChance.Value) { weights[i] += anomalyRandom.Next(Plugin.giftboxRarityAdditionMin.Value, Plugin.giftboxRarityAdditionMax.Value + 1); } if (anomalyRandom.Next(0, 100) < Plugin.giftboxRarityMultiplierChance.Value) { weights[i] = (int)((double)weights[i] * ((double)Plugin.giftboxRarityMultiplierMin.Value + (double)(Plugin.giftboxRarityMultiplierMax.Value - Plugin.giftboxRarityMultiplierMin.Value) * anomalyRandom.NextDouble()) / 100.0); } } } } internal static void AdjustGiftBoxValue(RoundManager roundmanager, GrabbableObject component, List<int> scrapValues) { if (component.itemProperties.itemId == 152767) { Random anomalyRandom = roundmanager.AnomalyRandom; if (anomalyRandom.Next(0, 100) < Plugin.giftboxValueAdditionChance.Value) { scrapValues[scrapValues.Count - 1] += anomalyRandom.Next(Plugin.giftboxValueAdditionMin.Value, Plugin.giftboxValueAdditionMax.Value + 1); } if (anomalyRandom.Next(0, 100) < Plugin.giftboxValueMultiplierChance.Value) { scrapValues[scrapValues.Count - 1] = (int)((double)scrapValues[scrapValues.Count - 1] * ((double)Plugin.giftboxValueMultiplierMin.Value + (double)(Plugin.giftboxValueMultiplierMax.Value - Plugin.giftboxValueMultiplierMin.Value) * anomalyRandom.NextDouble()) / 100.0); } } } [HarmonyPatch("SpawnScrapInLevel")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] internal static IEnumerable<CodeInstruction> SpawnScrapInLevel(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } ILStepper stepper = new ILStepper(methodIL, methodGenerator, methodBase); stepper.GotoIL((CodeInstruction code, int index) => code.StoresLocal(15) && index > 0 && CodeInstructionExtensions.LoadsConstant(stepper.Instructions[index - 1], 0L), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] For loop initialization (int j = 0;) not found"); stepper.GotoIL((CodeInstruction code) => code.opcode.FlowControl == FlowControl.Branch, null, 0, reverse: false, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] For loop branch to control statement (j < this.currentLevel.spawnableScrap.Count;) not found"); stepper.GotoIL((CodeInstruction code) => code.labels.Contains((Label)stepper.CurrentOperand), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] For loop control statement (j < this.currentLevel.spawnableScrap.Count;) not found"); stepper.GotoIL((CodeInstruction code) => code.LoadsProperty(typeof(List<SpawnableItemWithRarity>), "Count"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] Load Property List.Count (this.currentLevel.spawnableScrap.Count) not found"); List<CodeInstruction> list = (from code in stepper.GetIL(stepper.FindIL(ILPatterns.NextEmptyStack(-1), null, 0, reverse: true, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] Spawnable Scrap List (this.currentLevel.spawnableScrap) not found)")) select code.Clone()).ToList(); stepper.GotoIndex(0); stepper.GotoIL((CodeInstruction code) => code.StoresField(stepper.GetLocal(0).LocalType, "ScrapToSpawn"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] Store Field compilerClosureObj.ScrapToSpawn not found"); stepper.GotoIndex(null, 1); ILStepper iLStepper = stepper; List<CodeInstruction> list2 = new List<CodeInstruction>(); list2.Add(CodeInstructionPolyfills.LoadArgument(0)); list2.Add(CodeInstructionPolyfills.LoadLocal(0)); list2.Add(CodeInstructionPolyfills.LoadField(stepper.GetLocal(0).LocalType, "ScrapToSpawn")); list2.Add(CodeInstructionPolyfills.LoadLocal(2)); list2.AddRange(list); list2.Add(CodeInstructionPolyfills.Call(typeof(RoundManagerPatch), "AnomalouslySpawnGiftBoxes")); iLStepper.InsertIL(list2); stepper.GotoIL((CodeInstruction code) => code.StoresLocal(6), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] Store Local 6 (weights) not found"); stepper.GotoIndex(null, 1); ILStepper iLStepper2 = stepper; CodeInstruction item = CodeInstructionPolyfills.LoadArgument(0); CodeInstruction item2 = CodeInstructionPolyfills.LoadLocal(6); list2 = list; List<CodeInstruction> list3 = new List<CodeInstruction>(3 + list2.Count); list3.Add(item); list3.Add(item2); list3.AddRange(list2); list3.Add(CodeInstructionPolyfills.Call(typeof(RoundManagerPatch), "AdjustGiftBoxSpawnWeight")); iLStepper2.InsertIL(list3); stepper.GotoIL((CodeInstruction code) => code.StoresField(typeof(GrabbableObject), "scrapValue"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] Store field GrabbableObject.scrapValue not found"); stepper.GotoIL((CodeInstruction code) => code.StoresLocal(4), null, 0, reverse: true, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] Store Local 4 (num4) not found"); stepper.GotoIL(ILPatterns.NextEmptyStack(), null, 1, reverse: true, "[Patches.GiftBoxItemPatches.RoundManagerPatch.SpawnScrapInLevel] Load Local 4 (num4) not found"); stepper.InsertIL(new List<CodeInstruction>(4) { CodeInstructionPolyfills.LoadArgument(0), CodeInstructionPolyfills.LoadLocal(18), CodeInstructionPolyfills.LoadLocal(3), CodeInstructionPolyfills.Call(typeof(RoundManagerPatch), "AdjustGiftBoxValue") }); return stepper.Instructions; } } [HarmonyPatch] internal static class SaveFilePatch { internal static readonly string GiftBoxModdedParamsSaveKey = Plugin.harmony.Id + ".giftboxModdedParamsDict"; internal static Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams> GetGiftBoxModdedParamsDict() { Plugin.Log($"ES3 Key exists: {ES3.KeyExists(GiftBoxModdedParamsSaveKey, GameNetworkManager.Instance.currentSaveFileName)}"); if (!ES3.KeyExists(GiftBoxModdedParamsSaveKey, GameNetworkManager.Instance.currentSaveFileName)) { return new Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams>(); } CollectionExtensions.Do<KeyValuePair<int, GiftBoxItemPatch.GiftBoxModdedParams>>((IEnumerable<KeyValuePair<int, GiftBoxItemPatch.GiftBoxModdedParams>>)ES3.Load<Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams>>(GiftBoxModdedParamsSaveKey, GameNetworkManager.Instance.currentSaveFileName), (Action<KeyValuePair<int, GiftBoxItemPatch.GiftBoxModdedParams>>)delegate(KeyValuePair<int, GiftBoxItemPatch.GiftBoxModdedParams> keypair) { Plugin.Log($"\t{keypair.Key} {keypair.Value}"); }); return ES3.Load<Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams>>(GiftBoxModdedParamsSaveKey, GameNetworkManager.Instance.currentSaveFileName); } internal static void LoadGiftBoxModdedParams(Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams> dict, int index, GrabbableObject grabbable) { Plugin.Log($"Dict Key [{index}] exists: {dict.ContainsKey(index)}"); if (dict.ContainsKey(index)) { Plugin.Log($"\t[{index}] {dict[index]}"); ((Component)grabbable).gameObject.AddComponent<GiftBoxItemPatch.GiftBoxModdedBehavior>().Params = dict[index]; } } [HarmonyPatch(typeof(StartOfRound), "LoadShipGrabbableItems")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] internal static IEnumerable<CodeInstruction> LoadShipGrabbableItems(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.LoadsString("Ship grabbable items list loaded. Count: {0}"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.SaveFilePatch.LoadShipGrabbableItems] String \"Ship grabbable items list loaded. Count: {0}\" not found"); iLStepper.GotoIL(ILPatterns.NextEmptyStack(), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.SaveFilePatch.LoadShipGrabbableItems] Call Debug.Log not found"); iLStepper.GotoIndex(null, 1); LocalVariableInfo local = iLStepper.DeclareLocal(typeof(Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams>)); iLStepper.InsertIL(new List<CodeInstruction>(2) { CodeInstructionPolyfills.Call(typeof(SaveFilePatch), "GetGiftBoxModdedParamsDict"), CodeInstructionPolyfills.StoreLocal(local) }); iLStepper.GotoIL((CodeInstruction code) => code.StoresLocal(0)); iLStepper.GotoIndex(null, 1); iLStepper.InsertIL(new List<CodeInstruction>(4) { CodeInstructionPolyfills.LoadLocal(local), CodeInstructionPolyfills.LoadLocal(9), CodeInstructionPolyfills.LoadLocal(0), CodeInstructionPolyfills.Call(typeof(SaveFilePatch), "LoadGiftBoxModdedParams") }); return iLStepper.Instructions; } internal static void SetGiftBoxModdedParamsInDict(Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams> dict, int index, GrabbableObject grabbable) { GiftBoxItemPatch.GiftBoxModdedParams giftBoxModdedParams = ((Component)grabbable).GetComponent<GiftBoxItemPatch.GiftBoxModdedBehavior>(); if (giftBoxModdedParams != null) { dict.Add(index, giftBoxModdedParams); } } internal static void SaveGiftBoxModdedParamsDict(Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams> dict) { ES3.Save<Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams>>(GiftBoxModdedParamsSaveKey, dict, GameNetworkManager.Instance.currentSaveFileName); } [HarmonyPatch(typeof(GameNetworkManager), "SaveItemsInShip")] [HarmonyPriority(int.MinValue)] [HarmonyTranspiler] internal static IEnumerable<CodeInstruction> SaveItemsInShip(IEnumerable<CodeInstruction> methodIL, ILGenerator methodGenerator, MethodBase methodBase) { //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown if (Plugin.giftboxMechanicsDisabled.Value) { return methodIL; } ILStepper iLStepper = new ILStepper(methodIL, methodGenerator, methodBase); iLStepper.GotoIL((CodeInstruction code) => code.LoadsString("shipGrabbableItemIDs"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.SaveFilePatch.SaveItemsInShip] String \"shipGrabbableItemIDs\" not found"); iLStepper.InsertIL(new List<CodeInstruction>(4) { CodeInstructionPolyfills.LoadString(GiftBoxModdedParamsSaveKey), CodeInstructionPolyfills.LoadArgument(0), CodeInstructionPolyfills.LoadField(typeof(GameNetworkManager), "currentSaveFileName"), CodeInstructionPolyfills.Call(typeof(ES3), "DeleteKey", new Type[2] { typeof(string), typeof(string) }) }); iLStepper.GotoIL((CodeInstruction code) => code.StoresLocal(4)); iLStepper.GotoIndex(null, 1); LocalVariableInfo local = iLStepper.DeclareLocal(typeof(Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams>)); iLStepper.InsertIL(new List<CodeInstruction>(2) { CodeInstructionPolyfills.CallConstructor(typeof(Dictionary<int, GiftBoxItemPatch.GiftBoxModdedParams>)), CodeInstructionPolyfills.StoreLocal(local) }); iLStepper.GotoIL((CodeInstruction code) => code.LoadsString("Saved data for item type: {0} - {1}"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.SaveFilePatch.SaveItemsInShip] String \"Saved data for item type: {0} - {1}\" not found"); iLStepper.InsertIL(new List<CodeInstruction>(9) { CodeInstructionPolyfills.LoadLocal(local), CodeInstructionPolyfills.LoadLocal(1), CodeInstructionPolyfills.LoadProperty(typeof(List<int>), "Count"), CodeInstructionPolyfills.LoadConstant(1), new CodeInstruction(OpCodes.Sub, (object)null), CodeInstructionPolyfills.LoadLocal(0), CodeInstructionPolyfills.LoadLocal(6), new CodeInstruction(OpCodes.Ldelem_Ref, (object)null), CodeInstructionPolyfills.Call(typeof(SaveFilePatch), "SetGiftBoxModdedParamsInDict") }); iLStepper.GotoIL((CodeInstruction code) => code.LoadsString("shipGrabbableItemPos"), null, 0, reverse: false, "[Patches.GiftBoxItemPatches.SaveFilePatch.SaveItemsInShip] String \"shipGrabbableItemPos\" not found"); iLStepper.InsertIL(new List<CodeInstruction>(2) { CodeInstructionPolyfills.LoadLocal(local), CodeInstructionPolyfills.Call(typeof(SaveFilePatch), "SaveGiftBoxModdedParamsDict") }); return iLStepper.Instructions; } } } namespace LC_GiftBox_Config.libs.Probability { public static class Probability { public static int GetRandomWeightedIndex(List<double> weights, Random? randomSeed = null) { if (weights == null || weights.Count == 0) { Plugin.Log((LogLevel)4, "[libs.Probability.GetRandomWeightedIndex] Could not get random weighted index; list is empty or null."); return -1; } if (weights.Any((double weight) => weight < 0.0)) { Plugin.Log((LogLevel)4, "[libs.Probability.GetRandomWeightedIndex] Could not get random weighted index; list contains negative weights."); return -1; } if (randomSeed == null) { randomSeed = new Random(); } double num = weights.Sum(); if (num <= 0.0) { return randomSeed.Next(0, weights.Count); } double randomValue = randomSeed.NextDouble() * weights.Sum(); double accumulatedValue = 0.0; return weights.FindIndex((double weight) => (accumulatedValue += weight) > randomValue); } public static int GetRandomWeightedIndex(List<int> weights, Random? randomSeed = null) { if (weights == null || weights.Count == 0) { Plugin.Log((LogLevel)4, "[libs.Probability.GetRandomWeightedIndex] Could not get random weighted index; list is empty or null."); return -1; } if (weights.Any((int weight) => weight < 0)) { Plugin.Log((LogLevel)4, "[libs.Probability.GetRandomWeightedIndex] Could not get random weighted index; list contains negative weights."); return -1; } if (randomSeed == null) { randomSeed = new Random(); } int num = weights.Sum(); if (num <= 0) { return randomSeed.Next(0, weights.Count); } int randomValue = randomSeed.Next(0, num); int accumulatedValue = 0; return weights.FindIndex((int weight) => (accumulatedValue += weight) > randomValue); } } } namespace LC_GiftBox_Config.libs.LethalConfigNicerizer { internal static class LethalConfigNicerizer { internal const string LethalConfig_GUID = "ainavt.lc.lethalconfig"; internal static bool CanHasNicerizationPlease => Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"); [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static ConfigEntry<T> Nicerize<T>(ConfigEntry<T> entry, bool restartRequired = false) { if (entry is ConfigEntry<int>) { if (CanHasNicerizationPlease) { AddConfigItem(entry as ConfigEntry<int>, restartRequired); } } else if (entry is ConfigEntry<float>) { if (CanHasNicerizationPlease) { AddConfigItem(entry as ConfigEntry<float>, restartRequired); } } else if (entry is ConfigEntry<bool>) { if (CanHasNicerizationPlease) { AddConfigItem(entry as ConfigEntry<bool>, restartRequired); } } else if (entry is ConfigEntry<string>) { if (CanHasNicerizationPlease) { AddConfigItem(entry as ConfigEntry<string>, restartRequired); } } else { if (!(entry is ConfigEntry<Enum>)) { throw new ArgumentException($"[libs.LethalConfigNicerizer.Nicerize] Cannot Nicerize ConfigEntry<{typeof(T)}>!"); } if (CanHasNicerizationPlease) { AddConfigItem(entry as ConfigEntry<Enum>, restartRequired); } } return entry; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void AddConfigItem(ConfigEntry<int> entry, bool restartRequired = false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (((ConfigEntryBase)entry).Description.AcceptableValues != null) { LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(entry, restartRequired)); } else { LethalConfigManager.AddConfigItem((BaseConfigItem)new IntInputFieldConfigItem(entry, restartRequired)); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void AddConfigItem(ConfigEntry<float> entry, bool restartRequired = false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (((ConfigEntryBase)entry).Description.AcceptableValues != null) { LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(entry, restartRequired)); } else { LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatInputFieldConfigItem(entry, restartRequired)); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void AddConfigItem(ConfigEntry<bool> entry, bool restartRequired = false) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(entry, restartRequired)); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void AddConfigItem(ConfigEntry<string> entry, bool restartRequired = false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (((ConfigEntryBase)entry).Description.AcceptableValues != null) { LethalConfigManager.AddConfigItem((BaseConfigItem)new TextDropDownConfigItem(entry, restartRequired)); } else { LethalConfigManager.AddConfigItem((BaseConfigItem)new TextInputFieldConfigItem(entry, restartRequired)); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void AddConfigItem(ConfigEntry<Enum> entry, bool restartRequired = false) { LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<Enum>(entry, restartRequired)); } } } namespace LC_GiftBox_Config.libs.ILStepper { public static class ILPatterns { public static int? StackSizeDelta(StackBehaviour stackBehaviour) { switch (stackBehaviour) { case StackBehaviour.Pop0: return 0; case StackBehaviour.Pop1: return -1; case StackBehaviour.Pop1_pop1: return -2; case StackBehaviour.Popi: return -1; case StackBehaviour.Popi_pop1: return -2; case StackBehaviour.Popi_popi: return -2; case StackBehaviour.Popi_popi8: return -2; case StackBehaviour.Popi_popi_popi: return -3; case StackBehaviour.Popi_popr4: return -2; case StackBehaviour.Popi_popr8: return -2; case StackBehaviour.Popref: return -1; case StackBehaviour.Popref_pop1: return -2; case StackBehaviour.Popref_popi: return -2; case StackBehaviour.Popref_popi_popi: return -3; case StackBehaviour.Popref_popi_popi8: return -3; case StackBehaviour.Popref_popi_popr4: return -3; case StackBehaviour.Popref_popi_popr8: return -3; case StackBehaviour.Popref_popi_popref: return -3; case StackBehaviour.Push0: return 0; case StackBehaviour.Push1: return 1; case StackBehaviour.Push1_push1: return 2; case StackBehaviour.Pushi: return 1; case StackBehaviour.Pushi8: return 1; case StackBehaviour.Pushr4: return 1; case StackBehaviour.Pushr8: return 1; case StackBehaviour.Pushref: return 1; case StackBehaviour.Popref_popi_pop1: return -3; case StackBehaviour.Varpop: case StackBehaviour.Varpush: return null; default: throw new ArgumentOutOfRangeException($"stackBehaviour {stackBehaviour} is an invalid value"); } } public static int? StackSizeDelta(OpCode opCode, object operand) { if (opCode == OpCodes.Calli) { return null; } if (opCode.FlowControl == FlowControl.Call) { MethodInfo methodInfo = operand as MethodInfo; if (methodInfo == null) { return null; } int num = -methodInfo.GetParameters().Count(); if (opCode != OpCodes.Newobj && methodInfo.CallingConvention.HasFlag(CallingConventions.HasThis) && !methodInfo.CallingConvention.HasFlag(CallingConventions.ExplicitThis)) { num--; } if (opCode == OpCodes.Newobj || methodInfo.ReturnType != typeof(void)) { num++; } return num; } int? num2 = StackSizeDelta(opCode.StackBehaviourPush); int? num3 = StackSizeDelta(opCode.StackBehaviourPop); if (!num2.HasValue || !num3.HasValue) { return null; } return num2 + num3; } public static int? StackSizeDelta(CodeInstruction code) { return StackSizeDelta(code.opcode, code.operand); } public static bool EmptiesStack(OpCode opcode) { FlowControl flowControl = opcode.FlowControl; if (flowControl == FlowControl.Branch || (uint)(flowControl - 7) <= 1u) { return true; } return false; } public static bool EmptiesStack(CodeInstruction code) { return EmptiesStack(code.opcode); } public static Func<CodeInstruction, int, bool> NextEmptyStack(int startSize = 0) { return delegate(CodeInstruction code, int index) { if (EmptiesStack(code)) { return true; } int num = StackSizeDelta(code) ?? throw new ArgumentException($"[libs.ILPatterns.NextEmptyStack] Encountered uncountable instruction [{index}] {code}"); return (startSize += num) == 0; }; } } public class ILStepper { public readonly List<CodeInstruction> Instructions; public int CurrentIndex; public readonly ILGenerator Generator; public readonly Dictionary<int, LocalVariableInfo> Locals; public readonly Dictionary<int, Label> Labels; public CodeInstruction CurrentInstruction => Instructions[CurrentIndex]; public OpCode CurrentOpCode => CurrentInstruction.opcode; public object? CurrentOperand => CurrentInstruction.operand; public ILStepper(IEnumerable<CodeInstruction> codes, ILGenerator generator, MethodBase original, int index = 0) { Instructions = codes.ToList(); CurrentIndex = index; Generator = generator; Locals = (from code in Instructions select code.operand as LocalVariableInfo into local where local != null select local).Distinct().ToDictionary((LocalVariableInfo local) => local.LocalIndex, (LocalVariableInfo local) => local); Labels = Instructions.SelectMany((CodeInstruction code) => code.labels).Distinct().ToDictionary((Label label) => label.GetHashCode(), (Label label) => label); CollectionExtensions.DoIf<LocalVariableInfo>((IEnumerable<LocalVariableInfo>)original.GetMethodBody().LocalVariables, (Func<LocalVariableInfo, bool>)((LocalVariableInfo local) => !Locals.ContainsKey(local.LocalIndex)), (Action<LocalVariableInfo>)delegate(LocalVariableInfo local) { Locals.Add(local.LocalIndex, local); }); Instructions.ForEach(delegate(CodeInstruction code) { TrySetLocal(code, code); }); } public Label DeclareLabel() { Label label = Generator.DefineLabel(); Labels.Add(label.GetHashCode(), label); return label; } public LocalVariableInfo DeclareLocal(Type type, bool pinned = false) { LocalVariableInfo localVariableInfo = Generator.DeclareLocal(type, pinned); Locals.Add(localVariableInfo.LocalIndex, localVariableInfo); return localVariableInfo; } public LocalVariableInfo? TryGetLocal(int localIndex) { if (!Locals.TryGetValue(localIndex, out LocalVariableInfo value)) { return null; } return value; } public LocalVariableInfo? TryGetLocal(CodeInstruction codeWithLocal) { if (!CodeInstructionExtensions.IsLdloc(codeWithLocal, (LocalBuilder)null) && !CodeInstructionExtensions.IsStloc(codeWithLocal, (LocalBuilder)null)) { return null; } return TryGetLocal(codeWithLocal.LocalIndex()); } public LocalVariableInfo GetLocal(int localIndex, string errorMessage = "No such local variable!") { return TryGetLocal(localIndex) ?? throw new Exception($"[libs.ILTools.GetLocal] [{localIndex}] | {errorMessage}"); } public LocalVariableInfo GetLocal(CodeInstruction codeWithLocal, string errorMessage = "No such local variable!") { return TryGetLocal(codeWithLocal) ?? throw new Exception($"[libs.ILTools.GetLocal] [{codeWithLocal}] | {errorMessage}"); } public LocalVariableInfo? TrySetLocal(CodeInstruction code, LocalVariableInfo local) { CodeInstruction val; if (CodeInstructionExtensions.IsLdloc(code, (LocalBuilder)null)) { val = CodeInstructionPolyfills.LoadLocal(local, code.opcode == OpCodes.Ldloca || code.opcode == OpCodes.Ldloca_S); } else { if (!CodeInstructionExtensions.IsStloc(code, (LocalBuilder)null)) { return null; } val = CodeInstructionPolyfills.StoreLocal(local); } code.opcode = val.opcode; code.operand = val.operand; return local; } public LocalVariableInfo? TrySetLocal(CodeInstruction code, int localIndex) { LocalVariableInfo localVariableInfo = TryGetLocal(localIndex); if (localVariableInfo == null) { return null; } return TrySetLocal(code, localVariableInfo); } public LocalVariableInfo? TrySetLocal(CodeInstruction code, CodeInstruction codeWithLocal) { LocalVariableInfo localVariableInfo = TryGetLocal(codeWithLocal); if (localVariableInfo == null) { return null; } return TrySetLocal(code, localVariableInfo); } public LocalVariableInfo SetLocal(CodeInstruction code, LocalVariableInfo local, string errorMessage = "Could not set local!") { return TrySetLocal(code, local) ?? throw new Exception($"[libs.ILTools.SetLocal] [{code}, {local}] | {errorMessage}"); } public LocalVariableInfo SetLocal(CodeInstruction code, int localIndex, string errorMessage = "Could not set local!") { return TrySetLocal(code, localIndex) ?? throw new Exception($"[libs.ILTools.SetLocal] [{code}, {localIndex}] | {errorMessage}"); } public LocalVariableInfo SetLocal(CodeInstruction code, CodeInstruction codeWithLocal, string errorMessage = "Could not set local!") { return TrySetLocal(code, codeWithLocal) ?? throw new Exception($"[libs.ILTools.SetLocal] [{code}, {codeWithLocal}] | {errorMessage}"); } public int? TryFindIL(Func<CodeInstruction, int, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false) { index = (index ?? CurrentIndex) + offset + (reverse ? (-1) : 0); while (index >= 0 && index < Instructions.Count) { if (searchCondition(Instructions[index.Value], index.Value)) { return index; } index += ((!reverse) ? 1 : (-1)); } return null; } public int? TryFindIL(Func<CodeInstruction, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false) { Func<CodeInstruction, bool> searchCondition2 = searchCondition; return TryFindIL((CodeInstruction code, int index) => searchCondition2(code), index, offset, reverse); } public int FindIL(Func<CodeInstruction, int, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false, string errorMessage = "Not found!") { int valueOrDefault = index.GetValueOrDefault(); if (!index.HasValue) { valueOrDefault = CurrentIndex; index = valueOrDefault; } return TryFindIL(searchCondition, index, offset, reverse) ?? throw new Exception(string.Format("[libs.ILTools.FindIL] [{0}, {1}, {2} ({3})] | {4}", searchCondition, index, reverse, reverse ? "reverse" : "forward", errorMessage)); } public int FindIL(Func<CodeInstruction, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false, string errorMessage = "Not found!") { int valueOrDefault = index.GetValueOrDefault(); if (!index.HasValue) { valueOrDefault = CurrentIndex; index = valueOrDefault; } return TryFindIL(searchCondition, index, offset, reverse) ?? throw new Exception(string.Format("[libs.ILTools.FindIL] [{0}, {1}, {2} ({3})] | {4}", searchCondition, index, reverse, reverse ? "reverse" : "forward", errorMessage)); } public int? TryGotoIL(Func<CodeInstruction, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false) { index = TryFindIL(searchCondition, index, offset, reverse); CurrentIndex = index ?? CurrentIndex; return index; } public int? TryGotoIL(Func<CodeInstruction, int, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false) { index = TryFindIL(searchCondition, index, offset, reverse); CurrentIndex = index ?? CurrentIndex; return index; } public int GotoIL(Func<CodeInstruction, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false, string errorMessage = "Not found!") { int valueOrDefault = index.GetValueOrDefault(); if (!index.HasValue) { valueOrDefault = CurrentIndex; index = valueOrDefault; } return CurrentIndex = TryFindIL(searchCondition, index, offset, reverse) ?? throw new Exception(string.Format("[libs.ILTools.GotoIL] [{0}, {1}, {2} ({3})] | {4}", searchCondition, index, reverse, reverse ? "reverse" : "forward", errorMessage)); } public int GotoIL(Func<CodeInstruction, int, bool> searchCondition, int? index = null, int offset = 0, bool reverse = false, string errorMessage = "Not found!") { int valueOrDefault = index.GetValueOrDefault(); if (!index.HasValue) { valueOrDefault = CurrentIndex; index = valueOrDefault; } return CurrentIndex = TryFindIL(searchCondition, index, offset, reverse) ?? throw new Exception(string.Format("[libs.ILTools.GotoIL] [{0}, {1}, {2} ({3})] | {4}", searchCondition, index, reverse, reverse ? "reverse" : "forward", errorMessage)); } public int? TryFindIndex(int? index = null, int offset = 0, int leftBoundOffset = 0, int rightBoundOffset = 1) { index = (index ?? CurrentIndex) + offset; if (index < leftBoundOffset || index > Instructions.Count - 1 + rightBoundOffset) { return null; } return index; } public int FindIndex(int? index = null, int offset = 0, int leftBoundOffset = 0, int rightBoundOffset = 1, string errorMessage = "Out of bounds!") { int valueOrDefault = index.GetValueOrDefault(); if (!index.HasValue) { valueOrDefault = CurrentIndex; index = valueOrDefault; } return TryFindIndex(index, offset, leftBoundOffset, rightBoundOffset) ?? throw new Exception($"[libs.ILTools.FindIndex] [{index + offset} ({index} + {offset}), {leftBoundOffset} (0 + {leftBoundOffset}), {Instructions.Count - 1 + rightBoundOffset} ({Instructions.Count - 1} + {rightBoundOffset})] | {errorMessage}"); } public int? TryGotoIndex(int? index = null, int offset = 0, int leftBoundOffset = 0, int rightBoundOffset = 1) { index = TryFindIndex(index, offset, leftBoundOffset, rightBoundOffset); CurrentIndex = index ?? CurrentIndex; return index; } public int GotoIndex(int? index = null, int offset = 0, int leftBoundOffset = 0, int rightBoundOffset = 1, string errorMessage = "Out of bounds!") { int valueOrDefault = index.GetValueOrDefault(); if (!index.HasValue) { valueOrDefault = CurrentIndex; index = valueOrDefault; } return CurrentIndex = TryFindIndex(index, offset, leftBoundOffset, rightBoundOffset) ?? throw new Exception($"[libs.ILTools.GotoIndex] [{index + offset} ({index} + {offset}), {leftBoundOffset} (0 + {leftBoundOffset}), {Instructions.Count - 1 + rightBoundOffset} ({Instructions.Count - 1} + {rightBoundOffset})] | {errorMessage}"); } public List<CodeInstruction>? TryInsertIL(List<CodeInstruction> codeRange, int? index = null, bool shiftCurrentIndex = true, bool pinLabels = true, bool pinBlocks = true) { index = TryFindIndex(index); if (!index.HasValue) { return null; } codeRange = ((I