using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using HarmonyLib; using MelonLoader; using MelonLoader.Melons; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using Polyfill.Boot; using Polyfill.Bridges; using Polyfill.Bridges.Steps.S0_4_5f2_To_0_4_6f5; using Polyfill.Contract; using Polyfill.Core; using Polyfill.Dynamic; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Plugin), "Polyfill.Boot", "0.11.16", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Polyfill")] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonPriority(int.MinValue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("DooDesch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © DooDesch")] [assembly: AssemblyFileVersion("0.11.16.0")] [assembly: AssemblyInformationalVersion("0.11.16+a991f1874ad4639ca4259d22a7773c7b8489caa5")] [assembly: AssemblyProduct("Polyfill.Boot")] [assembly: AssemblyTitle("Polyfill.Boot")] [assembly: AssemblyVersion("0.11.16.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 DooDesch { internal static class ModVersion { internal const string Current = "0.11.16"; } } namespace Polyfill.Bridges { internal sealed class Bridge { internal string Assembly; internal string DeclaringType; internal string OldName; internal int ParameterCount; internal string Because; internal Func Emit; internal string Creates; internal string[] ParameterTypes; internal BridgeSet Set; internal bool AllowOverload; internal bool Unprompted; internal string Id { get { string text = DeclaringType ?? ""; int num = text.LastIndexOfAny(new char[2] { '.', '/' }); if (num >= 0) { text = text.Substring(num + 1); } string text2 = (OldName ?? "").Replace("get_", "get-").Replace("set_", "set-"); string text3 = (text + "-" + text2).ToLowerInvariant(); string[] parameterTypes = ParameterTypes; if (parameterTypes != null && parameterTypes.Length > 0) { string text4 = ParameterTypes[0]; int num2 = text4.LastIndexOfAny(new char[2] { '.', '/' }); text3 = text3 + "-" + ((num2 >= 0) ? text4.Substring(num2 + 1) : text4).ToLowerInvariant(); } return text3; } } internal bool Fits(IReadOnlyList parameterTypes) { if (ParameterTypes == null) { return true; } if (parameterTypes == null || parameterTypes.Count != ParameterTypes.Length) { return false; } for (int i = 0; i < ParameterTypes.Length; i++) { if (!string.Equals(ParameterTypes[i], parameterTypes[i], StringComparison.Ordinal)) { return false; } } return true; } internal bool Verified(GameVersion game) { if (Set != null) { return Set.VerifiedRange.Allows(game); } return true; } } internal sealed class TypeRename { internal string Assembly; internal string OldFullName; internal string NewFullName; internal string Because; internal bool ByNativeClass; internal Answer[] Answers; internal BridgeSet Set; } internal sealed class Answer { internal string Name; internal string Returns; internal string[] Takes; internal Func Emit; } internal abstract class BridgeSet { private List _bridges; private List _renames; private VersionRange _verified; internal abstract string Step { get; } internal abstract string From { get; } internal abstract string VerifiedTo { get; } internal IReadOnlyList Renames { get { if (_renames != null) { return _renames; } _renames = new List(); foreach (TypeRename item in DeclareRenames()) { if (item != null) { item.Set = this; _renames.Add(item); } } return _renames; } } internal IReadOnlyList Bridges { get { if (_bridges != null) { return _bridges; } _bridges = new List(); foreach (Bridge item in Declare()) { if (item != null) { item.Set = this; _bridges.Add(item); } } return _bridges; } } internal VersionRange VerifiedRange => _verified ?? (_verified = VersionRange.Parse(From + ".." + VerifiedTo)); internal abstract IEnumerable Declare(); internal virtual IEnumerable DeclareRenames() { return Array.Empty(); } } internal static class Registry { private static readonly BridgeSet[] Sets = new BridgeSet[1] { new Set() }; internal static IEnumerable All => Sets; internal static IEnumerable Bridges() { BridgeSet[] sets = Sets; foreach (BridgeSet bridgeSet in sets) { foreach (Bridge bridge in bridgeSet.Bridges) { yield return bridge; } } } internal static Bridge Find(string assembly, string declaringType, string oldName, int parameterCount, IReadOnlyList parameterTypes = null) { Bridge bridge = null; foreach (Bridge item in Bridges()) { if (item.OldName != oldName || item.DeclaringType != declaringType || item.ParameterCount != parameterCount || !string.Equals(item.Assembly, assembly, StringComparison.OrdinalIgnoreCase)) { continue; } if (item.ParameterTypes == null) { if (bridge == null) { bridge = item; } } else if (item.Fits(parameterTypes)) { return item; } } if (parameterTypes != null) { foreach (Bridge item2 in Bridges()) { if (item2.OldName == oldName && item2.DeclaringType == declaringType && item2.ParameterCount == parameterCount && item2.ParameterTypes != null && string.Equals(item2.Assembly, assembly, StringComparison.OrdinalIgnoreCase)) { return null; } } } return bridge; } internal static Bridge FindByName(string assembly, string declaringType, string name, int parameterCount) { Bridge bridge = null; foreach (Bridge item in Bridges()) { if (!(item.OldName != name) && !(item.DeclaringType != declaringType) && string.Equals(item.Assembly, assembly, StringComparison.OrdinalIgnoreCase) && (parameterCount < 0 || item.ParameterCount == parameterCount)) { if (bridge != null) { return null; } bridge = item; } } return bridge; } internal static Bridge Creator(string assembly, string typeFullName) { Bridge bridge = null; foreach (Bridge item in Bridges()) { if (!(item.Creates != typeFullName) && string.Equals(item.Assembly, assembly, StringComparison.OrdinalIgnoreCase)) { if (bridge != null) { return null; } bridge = item; } } return bridge; } internal static TypeRename FindType(string assembly, string oldFullName) { BridgeSet[] sets = Sets; for (int i = 0; i < sets.Length; i++) { foreach (TypeRename rename in sets[i].Renames) { if (rename.OldFullName == oldFullName && string.Equals(rename.Assembly, assembly, StringComparison.OrdinalIgnoreCase)) { return rename; } } } return null; } internal static string PastTheHorizon(GameVersion game) { if (!game.IsKnown) { return null; } GameVersion gameVersion = GameVersion.Unknown; BridgeSet[] sets = Sets; for (int i = 0; i < sets.Length; i++) { GameVersion gameVersion2 = GameVersion.Parse(sets[i].VerifiedTo); if (!gameVersion.IsKnown || gameVersion2 > gameVersion) { gameVersion = gameVersion2; } } if (!gameVersion.IsKnown || game <= gameVersion) { return null; } return $"Schedule I {game} is newer than anything these repairs were read against ({gameVersion}). " + "They still run: each one checks the game you have before it does anything. What no longer fits is named in the log and in `polyfillexport`, which is what turns it into an update."; } } } namespace Polyfill.Bridges.Steps.S0_4_5f2_To_0_4_6f5 { internal sealed class Set : BridgeSet { private const string Stations = "Il2CppScheduleOne.UI.Stations."; private const string StationSweep = "0.4.6 factored the station screens onto a shared StationInterface base and renamed the four that still said Canvas; same members, same namespace, one word different"; private const string StationOwner = "the screen's own station was called after the station (PackagingStationCanvas.PackagingStation, MixingStationCanvas.MixingStation) and 0.4.6 calls both Station - the other five screens kept theirs, so this is two names and not a pattern"; private static readonly List Renamed_ = new List { Pair("Il2CppScheduleOne.UI.Stations.MixingStationCanvas", "Il2CppScheduleOne.UI.Stations.MixingStationInterface"), Pair("Il2CppScheduleOne.UI.Stations.ChemistryStationCanvas", "Il2CppScheduleOne.UI.Stations.ChemistryStationInterface"), Pair("Il2CppScheduleOne.UI.Stations.CauldronCanvas", "Il2CppScheduleOne.UI.Stations.CauldronInterface"), Pair("Il2CppScheduleOne.UI.Stations.DryingRackCanvas", "Il2CppScheduleOne.UI.Stations.DryingRackInterface"), new TypeRename { Assembly = "Assembly-CSharp", OldFullName = "Il2CppScheduleOne.UI.MainMenu.MainMenuScreen", NewFullName = "Il2CppScheduleOne.UI.MainMenu.MenuScreen", Because = "the base class of every main-menu screen was renamed in place: 0.4.5f2 has ContinueScreen : MainMenuScreen, 0.4.6f13 has ContinueScreen : MenuScreen, and MenuScreen is the only type of that name on the build" }, new TypeRename { Assembly = "Assembly-CSharp", OldFullName = "Il2CppScheduleOne.UI.Handover.HandoverScreenPriceSelector", NewFullName = "Il2CppScheduleOne.UI.AmountSelector", Because = "the price control became the game's general amount box in 0.4.6 and moved out of the handover namespace; HandoverScreen.PriceSelector is an AmountSelector now" }, new TypeRename { Assembly = "Assembly-CSharp", OldFullName = "Il2CppScheduleOne.UI.InputPromptsCanvas", NewFullName = "Il2CppScheduleOne.UI.Input.InputPromptsManager", ByNativeClass = true, Answers = new Answer[4] { new Answer { Name = "LoadModule", Takes = new string[1] { "System.String" }, Emit = EmitLoadModule }, new Answer { Name = "UnloadModule", Emit = EmitUnloadModule }, new Answer { Name = "get_currentModuleLabel", Returns = "System.String", Emit = EmitCurrentModuleLabel }, new Answer { Name = "set_currentModuleLabel", Takes = new string[1] { "System.String" } } }, Because = "InputPromptsCanvas is gone since 0.4.6f5 and InputPromptsManager took over with a panel dictionary instead of one module slot - so the name is put back around the manager's native class, and the three members it needs call the manager, keeping the id they loaded because the manager has no current one" } }; internal const string StackLabel = "Polyfill"; private const string Npc = "Il2CppScheduleOne.NPCs.NPC"; private const string Inv = "Il2CppScheduleOne.NPCs.NPCInventory"; private static readonly string[] BasicInfo = new string[2] { "NPCData", "BasicInfo" }; private static readonly string[] Appearance = new string[2] { "NPCData", "Appearance" }; private static readonly string[] Interaction = new string[2] { "NPCData", "Interaction" }; private static readonly string[] Messaging = new string[2] { "NPCData", "Messaging" }; private const string SpeedController = "Il2CppScheduleOne.NPCs.NPCSpeedController"; private static readonly string[] Inventory = new string[3] { "_npc", "NPCData", "Inventory" }; private const bool Write = true; private const bool Read = false; private static readonly string[] NoParameters = Array.Empty(); private const string Storage = "Il2CppScheduleOne.UI.StorageMenu"; private const string Owner = "Il2CppScheduleOne.ItemFramework.IItemSlotOwner"; private const string Text = "System.String"; private static readonly object[] OneCallback = new object[1]; private const string Speed = "npc.NPCData.Movement, which is where NPCMovement's own getter reads it from (NPCMovement.cs:170-172)"; private const string StationCanvas = "0.4.6 pulled the canvas off every station screen into the shared StationInterface base and renamed it _canvas"; private const string Avatar = "Il2CppScheduleOne.AvatarFramework.Avatar"; private const string PlayerType = "Il2CppScheduleOne.PlayerScripts.Player"; private const string PlayerToggle = "Player.cs:1423-1441 until 0.4.5f2; 0.4.6 deleted both and rewrote its own three callers to register a UI element instead, leaving every line these ran still there"; private const string Number = "System.Single"; private const string Pickpocketed = "NPCInventory.cs:40 until 0.4.5f2; the same InteractableObject under the name the private field carries now, which NPCInventory.cs:338-348 sets the pickpocket state on"; private const string ShapeKeys = "bodyOnly stopped the method before the accessory loop; 0.4.6 dropped the flag and always runs that loop, so the two-argument form is what passing false always did (Avatar.cs:292-297)"; private const string NameSplit = "NPC.cs:63-69 until 0.4.5f2, now BasicInfo.cs:4-7"; private const string Hideable = "NPC.cs:130 until 0.4.5f2, now Messaging.cs:11 - the same default and the same use, moved into the NPCData object with the rest of the per-NPC settings"; private const string Summon = "NPC.cs:116 until 0.4.5f2, now Interaction.cs:8 - and the game reads it from there in NPCEnterableBuilding.cs:96"; private const string SlotCount = "NPCInventory.cs:45 until 0.4.5f2, now Inventory.InventorySlotCount, which NPCInventory.cs:62 builds the slots from"; private const string Renamed = "NPCInventory.cs:51-65 until 0.4.5f2; the value kept its meaning and lost its old name in Inventory.cs"; private const string Pickpocket = "NPCInventory.cs:47 until 0.4.5f2, now Inventory.CanBePickpocketed, read at NPCInventory.cs:372"; private const string Counteroffer = "Il2CppScheduleOne.UI.Phone.CounterofferInterface"; private static readonly string[] PriceSelector = new string[1] { "PriceSelector" }; private const string PriceSelectorType = "Il2CppScheduleOne.UI.AmountSelector"; private static readonly string[] DealerData = new string[1] { "DealerData" }; private const string CutMoved = "Dealer.cs:102 until 0.4.5f2, now DealerNPCData.SalesCutPercentage (:20) - and the payout reads it from there with the same expression the old field was used in (Dealer.cs:1892 against :2031 in 0.4.5f2)"; private const string SigningMoved = "Dealer.cs:100 until 0.4.5f2, now DealerNPCData.cs:17 with the same 500 default, copied across when a dealer's data is built (:40) - the same move DealerType made"; private const string Movement = "Il2CppScheduleOne.NPCs.NPCMovement"; private const string Amount = "Il2CppScheduleOne.UI.AmountSelector"; private const string CompassElement = "Il2CppScheduleOne.UI.Compass.CompassManager/Element"; private const string PriceControl = "the handover price control became the game's general amount box in 0.4.6; Price is SelectedAmount and SetPrice is SetAmount, same values (AmountSelector.cs)"; private static readonly string[] NpcSpeed = new string[3] { "npc", "NPCData", "Movement" }; private static readonly string[] NpcHealthData = new string[3] { "npc", "NPCData", "Health" }; private static readonly string[] SupplierData = new string[1] { "SupplierData" }; private const string ShopListings = "the same PhoneShopInterface.Listing[]; 0.4.6 keeps it on SupplierNPCData and Supplier.SupplierData is the way in"; private const string LobbyType = "Il2CppScheduleOne.Networking.Lobby"; private const string Blackjack = "Il2CppScheduleOne.Casino.UI.BlackjackInterface"; private const string RouletteTable = "Il2CppScheduleOne.Casino.UI.RTBInterface"; private static readonly string[] BetPanel = new string[1] { "BetPanel" }; private const string BetMoved = "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"; private const string PlayerCameraType = "Il2CppScheduleOne.PlayerScripts.PlayerCamera"; private const string MouseControllerType = "Il2CppScheduleOne.Input.MouseController"; private static readonly string[] OneBool = new string[1] { "System.Boolean" }; private const string CursorMoved = "the cursor flag left PlayerCamera for MouseController, which 0.4.6 added and which its LockMouse and FreeMouse write the same way the camera's used to (MouseController.cs:9,13,25)"; private const string PlayerManager = "Il2CppScheduleOne.PlayerScripts.PlayerManager"; private const string PlayerLookups = "0.4.6 moved the player lookups off Player onto PlayerManager with the same names, parameters and return type; the game's own callers went with them (Supplier.cs:236 is one)"; private const string StructArrayName = "Il2CppStructArray`1"; private const string PriceBox = "CounterofferInterface.cs:20 held the price box directly until 0.4.5f2; 0.4.6 wraps it in an AmountSelector, whose _inputField is the same control (AmountSelector.cs:19)"; private const string Emitter = "Il2CppScheduleOne.VoiceOver.VOEmitter"; private const string Camera = "Il2CppScheduleOne.PlayerScripts.PlayerCamera"; private const string AmountSelector = "Il2CppScheduleOne.UI.AmountSelector"; private static readonly string[] NoHops = new string[0]; private const string BotanistConfig = "Il2CppScheduleOne.Management.BotanistConfiguration"; private const string PriceRenamed = "0.4.6 turned the handover price selector into the general amount box, and Price into SelectedAmount on it - same float, same meaning (AmountSelector.cs:27)"; private const string Packaging = "Il2CppScheduleOne.ObjectScripts.PackagingStation"; private const string Bool = "System.Boolean"; private const string GameplayMenu = "Il2CppScheduleOne.UI.GameplayMenu"; private const string SleepCanvas = "Il2CppScheduleOne.UI.SleepCanvas"; private const string DealerType = "Il2CppScheduleOne.Economy.Dealer"; private const string DealerDataType = "Il2CppScheduleOne.NPCs.Framework.DealerNPCData"; private const string DealerCut = "0.4.6 moved the dealer's cut onto the data object the NPC carries: 0.4.5f2 had a serialized Cut field on Dealer defaulting to 0.2f, 0.4.6f13 has DealerNPCData.SalesCutPercentage with the same type and the same default, and the consumer line is the same expression with one identifier swapped - ChangeCash(payment * (1f - Cut)) became ChangeCash(payment * (1f - DealerData.SalesCutPercentage)) (Dealer.cs:132, DealerNPCData.cs:17)"; private const string Clipboard = "Il2CppScheduleOne.Tools.ManagementClipboard"; private const string Customer = "Il2CppScheduleOne.Economy.CustomerData"; private const string VoDatabase = "VOEmitter.cs:12 until 0.4.5f2 held one serialized Database field, and Play() read it; 0.4.6 split it into a default and a current one and Play() reads _currentDatabase"; private const string VoPitch = "VOEmitter.cs:15 until 0.4.5f2; Play() multiplied PitchMultiplier by the runtime one, and 0.4.6 multiplies _defaultPitch by _runtimePitchMultiplier in the same expression"; private const string Crosshair = "the crosshair became a parameter; true is what the call did before it existed (PlayerCamera.cs:483-490)"; private static readonly List All = new List { new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.NPCs.NPCMovement", OldName = "get_MovementSpeedScale", ParameterCount = 0, Because = "the field was folded into UpdateSpeed(); the same value is now SpeedController.ActiveSpeedControl.speed * SpeedController.SpeedMultiplier", Emit = EmitMovementSpeedScaleGetter }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.NPCs.NPCMovement", OldName = "set_MovementSpeedScale", ParameterCount = 1, Because = "writing the field wrote the BASE speed the controller derived; the base slot is now a priority-0 entry on the speed stack, which everything the game does outranks", Emit = EmitMovementSpeedScaleSetter }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.NPCs.NPC", OldName = "OverrideAggression", ParameterCount = 1, Because = "Aggression became a read-only view over AggressionController; vanilla's own migration of this call is MethInstance.cs:51", Emit = EmitOverrideAggression }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Management.ManagementInterface", OldName = "get_NPCSelector", ParameterCount = 0, Because = "0.4.6 removed the NPC selector screen with no replacement and left its own stub behind (NPCFieldUI.cs:79 logs \"NPCSelector not implemented\"). The only use is a null check for \"is that screen open\", and a screen that does not exist is not open - see Removed.cs for why answering costs less than refusing", Creates = "Il2CppScheduleOne.UI.Management.NPCSelector", Emit = Removed.EmitNpcSelectorGetter }, Moved("Il2CppScheduleOne.UI.Phone.Delivery.DeliveryApp", "StatusDisplayPrefab", write: false, NoHops, "_deliveryStatusDisplayPrefab", "the same DeliveryStatusDisplay prefab, kept in a private field now and instantiated into the same StatusDisplayContainer (DeliveryApp.cs:332)"), Moved("Il2CppScheduleOne.Management.BotanistConfiguration", "AssignedStations", write: false, NoHops, "Assigns", "BotanistConfiguration.cs:27 is the same ObjectListField, taking the same pots, racks and beds (:15) with the same cap (:61); only the name moved"), Unprompted(Moved("Il2CppScheduleOne.UI.AmountSelector", "Price", write: false, NoHops, "SelectedAmount", "0.4.6 turned the handover price selector into the general amount box, and Price into SelectedAmount on it - same float, same meaning (AmountSelector.cs:27)")), Unprompted(Moved("Il2CppScheduleOne.UI.AmountSelector", "Price", write: true, NoHops, "SelectedAmount", "0.4.6 turned the handover price selector into the general amount box, and Price into SelectedAmount on it - same float, same meaning (AmountSelector.cs:27)")), Moved("Il2CppScheduleOne.NPCs.NPC", "ID", write: true, BasicInfo, "ID", "NPC.cs:63-69 until 0.4.5f2, now BasicInfo.cs:4-7"), Moved("Il2CppScheduleOne.NPCs.NPC", "FirstName", write: true, BasicInfo, "FirstName", "NPC.cs:63-69 until 0.4.5f2, now BasicInfo.cs:4-7"), Moved("Il2CppScheduleOne.NPCs.NPC", "LastName", write: true, BasicInfo, "LastName", "NPC.cs:63-69 until 0.4.5f2, now BasicInfo.cs:4-7"), Moved("Il2CppScheduleOne.NPCs.NPC", "hasLastName", write: true, BasicInfo, "HasLastName", "NPC.cs:63-69 until 0.4.5f2, now BasicInfo.cs:4-7"), Moved("Il2CppScheduleOne.NPCs.NPC", "MugshotSprite", write: true, Appearance, "Mugshot", "NPC.cs:71 until 0.4.5f2, now Appearance.Mugshot"), Moved("Il2CppScheduleOne.NPCs.NPC", "CanBeSummoned", write: true, Interaction, "CanBeSummoned", "NPC.cs:116 until 0.4.5f2, now Interaction.cs:8 - and the game reads it from there in NPCEnterableBuilding.cs:96"), Moved("Il2CppScheduleOne.NPCs.NPC", "CanBeSummoned", write: false, Interaction, "CanBeSummoned", "NPC.cs:116 until 0.4.5f2, now Interaction.cs:8 - and the game reads it from there in NPCEnterableBuilding.cs:96"), NowStatic("Il2CppScheduleOne.NPCs.NPCSpeedController", "get_DefaultWalkSpeed", 0, "get_DefaultNormalizedSpeed", "NPCSpeedController.cs:29 until 0.4.5f2, where nothing ever wrote it; 0.4.6 makes it the const DefaultNormalizedSpeed = 0.08f (:27), the same value it was initialised to"), Moved("Il2CppScheduleOne.NPCs.NPC", "ConversationCanBeHidden", write: true, Messaging, "ConversationCanBeHidden", "NPC.cs:130 until 0.4.5f2, now Messaging.cs:11 - the same default and the same use, moved into the NPCData object with the rest of the per-NPC settings"), Moved("Il2CppScheduleOne.NPCs.NPC", "ConversationCanBeHidden", write: false, Messaging, "ConversationCanBeHidden", "NPC.cs:130 until 0.4.5f2, now Messaging.cs:11 - the same default and the same use, moved into the NPCData object with the rest of the per-NPC settings"), Moved("Il2CppScheduleOne.NPCs.NPCInventory", "SlotCount", write: true, Inventory, "InventorySlotCount", "NPCInventory.cs:45 until 0.4.5f2, now Inventory.InventorySlotCount, which NPCInventory.cs:62 builds the slots from"), Moved("Il2CppScheduleOne.NPCs.NPCInventory", "SlotCount", write: false, Inventory, "InventorySlotCount", "NPCInventory.cs:45 until 0.4.5f2, now Inventory.InventorySlotCount, which NPCInventory.cs:62 builds the slots from"), Moved("Il2CppScheduleOne.NPCs.NPCInventory", "ClearInventoryEachNight", write: true, Inventory, "ClearInventoryOnNewDay", "NPCInventory.cs:51-65 until 0.4.5f2; the value kept its meaning and lost its old name in Inventory.cs"), Moved("Il2CppScheduleOne.NPCs.NPCInventory", "RandomCash", write: true, Inventory, "RandomizeCash", "NPCInventory.cs:51-65 until 0.4.5f2; the value kept its meaning and lost its old name in Inventory.cs"), Moved("Il2CppScheduleOne.NPCs.NPCInventory", "RandomItems", write: true, Inventory, "RandomizeInventory", "NPCInventory.cs:51-65 until 0.4.5f2; the value kept its meaning and lost its old name in Inventory.cs"), Moved("Il2CppScheduleOne.NPCs.NPCInventory", "CanBePickpocketed", write: true, Inventory, "CanBePickpocketed", "NPCInventory.cs:47 until 0.4.5f2, now Inventory.CanBePickpocketed, read at NPCInventory.cs:372"), Moved("Il2CppScheduleOne.UI.Phone.CounterofferInterface", "PriceInput", write: false, PriceSelector, "_inputField", "CounterofferInterface.cs:20 held the price box directly until 0.4.5f2; 0.4.6 wraps it in an AmountSelector, whose _inputField is the same control (AmountSelector.cs:19)"), Moved("Il2CppScheduleOne.UI.Phone.CounterofferInterface", "price", write: false, PriceSelector, "SelectedAmount", "CounterofferInterface.cs:164 reads PriceSelector.SelectedAmount where the screen's own `price` field used to be, and AmountSelector.cs:63 is what writes it"), Onto("Il2CppScheduleOne.UI.Phone.CounterofferInterface", "ChangePrice", 1, PriceSelector, "ChangeAmount", "CounterofferInterface.cs:196-200 until 0.4.5f2 clamped price + change into its own field and wrote the box; AmountSelector.cs:56 is that line with the bounds the box carries (ChangeAmount -> SetAmount(SelectedAmount + change))"), Moved("Il2CppScheduleOne.NPCs.NPCHealth", "MaxHealth", write: true, NpcHealthData, "MaxHealth", "NPCHealth.cs:32 until 0.4.5f2, now Health.cs:8 - and NPCHealth.cs:82 reads it straight back from there, so a write goes to the value the getter answers with"), Moved("Il2CppScheduleOne.NPCs.NPCMovement", "WalkSpeed", write: true, NpcSpeed, "WalkSpeed", "npc.NPCData.Movement, which is where NPCMovement's own getter reads it from (NPCMovement.cs:170-172)"), Moved("Il2CppScheduleOne.NPCs.NPCMovement", "RunSpeed", write: true, NpcSpeed, "SprintSpeed", "npc.NPCData.Movement, which is where NPCMovement's own getter reads it from (NPCMovement.cs:170-172)"), Moved("Il2CppScheduleOne.Economy.Supplier", "OnlineShopItems", write: false, SupplierData, "DeliveryShopListings", "the same PhoneShopInterface.Listing[]; 0.4.6 keeps it on SupplierNPCData and Supplier.SupplierData is the way in"), Moved("Il2CppScheduleOne.Economy.Supplier", "OnlineShopItems", write: true, SupplierData, "DeliveryShopListings", "the same PhoneShopInterface.Listing[]; 0.4.6 keeps it on SupplierNPCData and Supplier.SupplierData is the way in"), Moved("Il2CppScheduleOne.Casino.UI.BlackjackInterface", "BetSlider", write: false, BetPanel, "_betSlider", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"), Moved("Il2CppScheduleOne.Casino.UI.BlackjackInterface", "BetAmount", write: false, BetPanel, "_betAmount", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"), Moved("Il2CppScheduleOne.Casino.UI.BlackjackInterface", "ReadyButton", write: false, BetPanel, "_readyButton", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"), Onto("Il2CppScheduleOne.Casino.UI.BlackjackInterface", "BetSliderChanged", 1, BetPanel, "BetSliderChanged", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)", new string[1] { "newValue" }), Onto("Il2CppScheduleOne.Casino.UI.BlackjackInterface", "RefreshDisplayedBet", 0, BetPanel, "RefreshDisplayedBet", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"), Moved("Il2CppScheduleOne.Casino.UI.RTBInterface", "BetSlider", write: false, BetPanel, "_betSlider", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"), Moved("Il2CppScheduleOne.Casino.UI.RTBInterface", "BetAmount", write: false, BetPanel, "_betAmount", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"), Moved("Il2CppScheduleOne.Casino.UI.RTBInterface", "ReadyButton", write: false, BetPanel, "_readyButton", "the betting half of a casino screen became CasinoGameBetPanel, which every casino game shares; the screen's own BetPanel is the way in (CasinoGameBetPanel.cs:20,23,26, 38, 103)"), ElsewhereStatic("Il2CppScheduleOne.PlayerScripts.PlayerCamera", "LockMouse", 0, "Il2CppScheduleOne.Input.MouseController", "PlayerCamera.cs:523 until 0.4.5f2, now MouseController.cs:11 with the same body; its showCrosshair guards the line the old one ran unconditionally, so true is the old behaviour", new object[1] { true }), ElsewhereStatic("Il2CppScheduleOne.PlayerScripts.PlayerCamera", "FreeMouse", 0, "Il2CppScheduleOne.Input.MouseController", "PlayerCamera.cs:534 until 0.4.5f2, now MouseController.cs:23 with the same body; its hideCrosshair guards the line the old one ran unconditionally, so true is the old behaviour", new object[1] { true }), Elsewhere("Il2CppScheduleOne.PlayerScripts.PlayerCamera", "get_isCursorShowing", NoParameters, "Il2CppScheduleOne.Input.MouseController", "the cursor flag left PlayerCamera for MouseController, which 0.4.6 added and which its LockMouse and FreeMouse write the same way the camera's used to (MouseController.cs:9,13,25)", "get_IsMouseVisible"), Elsewhere("Il2CppScheduleOne.PlayerScripts.PlayerCamera", "set_isCursorShowing", OneBool, "Il2CppScheduleOne.Input.MouseController", "the cursor flag left PlayerCamera for MouseController, which 0.4.6 added and which its LockMouse and FreeMouse write the same way the camera's used to (MouseController.cs:9,13,25)", "set_IsMouseVisible"), Elsewhere("Il2CppScheduleOne.PlayerScripts.Player", "GetPlayer", new string[1] { "System.String" }, "Il2CppScheduleOne.PlayerScripts.PlayerManager", "0.4.6 moved the player lookups off Player onto PlayerManager with the same names, parameters and return type; the game's own callers went with them (Supplier.cs:236 is one)"), Elsewhere("Il2CppScheduleOne.PlayerScripts.Player", "GetPlayer", new string[1] { "Il2CppFishNet.Connection.NetworkConnection" }, "Il2CppScheduleOne.PlayerScripts.PlayerManager", "0.4.6 moved the player lookups off Player onto PlayerManager with the same names, parameters and return type; the game's own callers went with them (Supplier.cs:236 is one)"), Elsewhere("Il2CppScheduleOne.PlayerScripts.Player", "GetPlayerByName", new string[1] { "System.String" }, "Il2CppScheduleOne.PlayerScripts.PlayerManager", "0.4.6 moved the player lookups off Player onto PlayerManager with the same names, parameters and return type; the game's own callers went with them (Supplier.cs:236 is one)"), Elsewhere("Il2CppScheduleOne.PlayerScripts.Player", "GetRandomPlayer", new string[2] { "System.Boolean", "System.Boolean" }, "Il2CppScheduleOne.PlayerScripts.PlayerManager", "0.4.6 moved the player lookups off Player onto PlayerManager with the same names, parameters and return type; the game's own callers went with them (Supplier.cs:236 is one)"), Elsewhere("Il2CppScheduleOne.PlayerScripts.Player", "AreAllPlayersReadyToSleep", NoParameters, "Il2CppScheduleOne.PlayerScripts.PlayerManager", "0.4.6 moved the player lookups off Player onto PlayerManager with the same names, parameters and return type; the game's own callers went with them (Supplier.cs:236 is one)"), ElsewhereByShape("Il2CppScheduleOne.PlayerScripts.Player", "GetClosestPlayer", 3, "Il2CppScheduleOne.PlayerScripts.PlayerManager", "0.4.6 moved the player lookups off Player onto PlayerManager with the same names, parameters and return type; the game's own callers went with them (Supplier.cs:236 is one)", (MethodDefinition m) => ((ParameterReference)((MethodReference)m).Parameters[2]).ParameterType.IsGenericInstance), FromBase("Il2CppScheduleOne.UI.Stations.PackagingStationCanvas", "Canvas", "_canvas", "0.4.6 pulled the canvas off every station screen into the shared StationInterface base and renamed it _canvas"), FromBase("Il2CppScheduleOne.UI.Stations.BrickPressCanvas", "Canvas", "_canvas", "0.4.6 pulled the canvas off every station screen into the shared StationInterface base and renamed it _canvas"), FromBase("Il2CppScheduleOne.UI.Stations.LabOvenCanvas", "Canvas", "_canvas", "0.4.6 pulled the canvas off every station screen into the shared StationInterface base and renamed it _canvas"), FromBase("Il2CppScheduleOne.UI.Stations.MushroomSpawnStationInterface", "Canvas", "_canvas", "0.4.6 pulled the canvas off every station screen into the shared StationInterface base and renamed it _canvas"), new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.UI.AmountSelector", OldName = "get_onPriceChanged", ParameterCount = 0, Because = "the control became the game's general amount box, whose notification is the C# event OnAmountChanged (AmountSelector.cs:29) and not a UnityEvent - so the old name has no successor of that shape, and the callers guard it", Emit = EmitNoPriceEvent }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Networking.Lobby", OldName = "get_LobbySteamID", ParameterCount = 0, Because = "the id moved into the lobby service: Lobby.LobbyID is still declared and 0.4.6 writes it nowhere, so this reads SteamLobbyService._lobbyID, which is set when a lobby is created or entered (SteamLobbyService.cs:210,237)", Emit = EmitLobbySteamId }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Networking.Lobby", OldName = "get_LocalPlayerID", ParameterCount = 0, Because = "the field held this client's own Steam id, which is what SteamUser.GetSteamID() answers; 0.4.6 stopped keeping a copy of it on Lobby", Emit = EmitLocalPlayerId }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Networking.Lobby", OldName = "get_Players", ParameterCount = 0, Because = "the same ids, rebuilt from GetLobbyMemberIDs() - which SteamLobbyService.cs:178 builds out of the very array this used to be", Emit = EmitLobbyPlayers }, Moved("Il2CppScheduleOne.Economy.Dealer", "DealerType", write: false, DealerData, "DealerType", "Dealer.cs held the type itself until 0.4.5f2; 0.4.6 keeps every dealer-specific value on DealerNPCData and Dealer.DealerData is the way in"), Moved("Il2CppScheduleOne.Economy.Dealer", "Cut", write: false, DealerData, "SalesCutPercentage", "Dealer.cs:102 until 0.4.5f2, now DealerNPCData.SalesCutPercentage (:20) - and the payout reads it from there with the same expression the old field was used in (Dealer.cs:1892 against :2031 in 0.4.5f2)"), Moved("Il2CppScheduleOne.Economy.Dealer", "Cut", write: true, DealerData, "SalesCutPercentage", "Dealer.cs:102 until 0.4.5f2, now DealerNPCData.SalesCutPercentage (:20) - and the payout reads it from there with the same expression the old field was used in (Dealer.cs:1892 against :2031 in 0.4.5f2)"), Moved("Il2CppScheduleOne.Economy.Dealer", "SigningFee", write: true, DealerData, "SigningFee", "Dealer.cs:100 until 0.4.5f2, now DealerNPCData.cs:17 with the same 500 default, copied across when a dealer's data is built (:40) - the same move DealerType made"), Moved("Il2CppScheduleOne.Economy.Dealer", "SigningFee", write: false, DealerData, "SigningFee", "Dealer.cs:100 until 0.4.5f2, now DealerNPCData.cs:17 with the same 500 default, copied across when a dealer's data is built (:40) - the same move DealerType made"), NowCalled("Il2CppScheduleOne.VoiceOver.VOEmitter", "get_Database", 0, "get__currentDatabase", "VOEmitter.cs:12 until 0.4.5f2 held one serialized Database field, and Play() read it; 0.4.6 split it into a default and a current one and Play() reads _currentDatabase"), NowCalled("Il2CppScheduleOne.VoiceOver.VOEmitter", "set_Database", 1, "set__currentDatabase", "VOEmitter.cs:12 until 0.4.5f2 held one serialized Database field, and Play() read it; 0.4.6 split it into a default and a current one and Play() reads _currentDatabase"), NowCalled("Il2CppScheduleOne.VoiceOver.VOEmitter", "get_PitchMultiplier", 0, "get__defaultPitch", "VOEmitter.cs:15 until 0.4.5f2; Play() multiplied PitchMultiplier by the runtime one, and 0.4.6 multiplies _defaultPitch by _runtimePitchMultiplier in the same expression"), NowCalled("Il2CppScheduleOne.VoiceOver.VOEmitter", "set_PitchMultiplier", 1, "SetDefaultPitch", "VOEmitter.cs:15 until 0.4.5f2; Play() multiplied PitchMultiplier by the runtime one, and 0.4.6 multiplies _defaultPitch by _runtimePitchMultiplier in the same expression"), NowCalled("Il2CppScheduleOne.PlayerScripts.PlayerCrimeData", "set_SyncAccessor_k__BackingField", 1, "set_CurrentPursuitLevel", "the generated assembly carries the property without accessor methods under that name, and CurrentPursuitLevel's own setter is the same write - its getter is a plain `return CurrentPursuitLevel` (PlayerCrimeData.cs:151)"), new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.NPCs.NPC", OldName = "get_fullName", ParameterCount = 0, Because = "0.4.6 renamed fullName to FullName and moved the names it reads behind NPCData, which is null until an NPC is set up - the old one read fields that were never null, so this answers the empty string there instead of throwing", Emit = EmitNpcFullName }, NowCalled("Il2CppScheduleOne.PlayerScripts.Player", "get_CurrentAvatarSettings", 0, "get_CurrentBasicAppearance", "Player.cs:450 until 0.4.5f2, now :415 as CurrentBasicAppearance - the same BasicAvatarSettings with the same protected setter, saved by the same line (:754)"), NowCalled("Il2CppScheduleOne.UI.DialogueCanvas", "get_isActive", 0, "get_IsOpen", "DialogueCanvas.cs:57 until 0.4.5f2 and :60 now - the same `currentHandler != null`, renamed from isActive to IsOpen"), NowCalled("Il2CppScheduleOne.UI.Relations.RelationCircle", "get_AssignedNPC_ID", 0, "get_NPCId", "RelationCircle.cs:23 until 0.4.5f2 cached the id in a field; NPCId reads it off the assigned NPC and returns string.Empty for none, which is what the field held"), NowCalled("Il2CppScheduleOne.PlayerScripts.Health.PlayerHealth", "get_MAX_HEALTH", 0, "get_MaxHealth", "the same constant, renamed to PascalCase (PlayerHealth.cs:18)"), NowCalled("Il2CppScheduleOne.UI.StorageMenu", "get_CloseButton", 0, "get_CloseButtonContainer", "the same RectTransform, renamed when the button got its own container (StorageMenu.cs:24)"), NowCalled("Il2CppScheduleOne.NPCs.NPCInventory", "get_PickpocketIntObj", 0, "get__interactable", "NPCInventory.cs:40 until 0.4.5f2; the same InteractableObject under the name the private field carries now, which NPCInventory.cs:338-348 sets the pickpocket state on"), NowCalled("Il2CppScheduleOne.UI.AmountSelector", "SetPrice", 1, "SetAmount", "the handover price control became the game's general amount box in 0.4.6; Price is SelectedAmount and SetPrice is SetAmount, same values (AmountSelector.cs)", new string[1] { "price" }), NowCalled("Il2CppScheduleOne.UI.AmountSelector", "get_Price", 0, "get_SelectedAmount", "the handover price control became the game's general amount box in 0.4.6; Price is SelectedAmount and SetPrice is SetAmount, same values (AmountSelector.cs)"), NowCalled("Il2CppScheduleOne.UI.Compass.CompassManager/Element", "get_Transform", 0, "get_TargetTransform", "CompassManager.cs:32 until 0.4.5f2 was a public Transform field; 0.4.6 makes it a property the constructor fills from the same argument (CompassManager.cs:27-34)"), NowCalled("Il2CppScheduleOne.Economy.Dealer", "GetProductCount", 3, "GetOrderableProductQuantity", "the same three parameters in the same order and the same int back, and Dealer.cs:625 counts exactly what the old name says - the dealer's stock of one product within a quality range. The rename is older than the version archive, so this is read from the body rather than from a diff"), new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.UI.StorageMenu", OldName = "get_onClosed", ParameterCount = 0, Because = "StorageMenu.cs:35 until 0.4.5f2 was a UnityEvent the menu fired when it closed; 0.4.6 keeps a private Action instead, which nothing can subscribe to from outside - so the event is put back and Polyfill fires it", Emit = EmitStorageClosedEvent }, NowCalled("Il2CppScheduleOne.NPCs.NPCInventory", "set_PickpocketIntObj", 1, "set__interactable", "NPCInventory.cs:40 until 0.4.5f2; the same InteractableObject under the name the private field carries now, which NPCInventory.cs:338-348 sets the pickpocket state on"), NowCalled("Il2CppScheduleOne.UI.Stations.PackagingStationCanvas", "get_PackagingStation", 0, "get_Station", "the screen's own station was called after the station (PackagingStationCanvas.PackagingStation, MixingStationCanvas.MixingStation) and 0.4.6 calls both Station - the other five screens kept theirs, so this is two names and not a pattern"), NowCalled("Il2CppScheduleOne.UI.Stations.MixingStationInterface", "get_MixingStation", 0, "get_Station", "the screen's own station was called after the station (PackagingStationCanvas.PackagingStation, MixingStationCanvas.MixingStation) and 0.4.6 calls both Station - the other five screens kept theirs, so this is two names and not a pattern"), Dropped("Il2CppScheduleOne.AvatarFramework.Avatar", "ApplyShapeKeys", new string[2] { "System.Single", "System.Single" }, "System.Boolean", "bodyOnly stopped the method before the accessory loop; 0.4.6 dropped the flag and always runs that loop, so the two-argument form is what passing false always did (Avatar.cs:292-297)"), new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.AvatarFramework.Avatar", OldName = "set_InitialAvatarSettings", ParameterCount = 1, Because = "Avatar.cs until 0.4.5f2 kept the settings an avatar was built from; 0.4.6 dropped the field and nothing reads it any more, so the write is accepted and discarded - and no getter is offered, because there is nothing to give back", Emit = EmitForgottenSetter }, SplitInTwo(0), SplitInTwo(1), SplitInTwo(2), SplitInTwo(3), SplitInTwo(4), ReplacedByTwo(0), ReplacedByTwo(1), new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Economy.Dealer", OldName = "get_Cut", ParameterCount = 0, Because = "0.4.6 moved the dealer's cut onto the data object the NPC carries: 0.4.5f2 had a serialized Cut field on Dealer defaulting to 0.2f, 0.4.6f13 has DealerNPCData.SalesCutPercentage with the same type and the same default, and the consumer line is the same expression with one identifier swapped - ChangeCash(payment * (1f - Cut)) became ChangeCash(payment * (1f - DealerData.SalesCutPercentage)) (Dealer.cs:132, DealerNPCData.cs:17)", Emit = (ModuleDefinition module, TypeDefinition type) => EmitDealerCut(module, type, setter: false) }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Economy.Dealer", OldName = "set_Cut", ParameterCount = 1, ParameterTypes = new string[1] { "System.Single" }, Because = "0.4.6 moved the dealer's cut onto the data object the NPC carries: 0.4.5f2 had a serialized Cut field on Dealer defaulting to 0.2f, 0.4.6f13 has DealerNPCData.SalesCutPercentage with the same type and the same default, and the consumer line is the same expression with one identifier swapped - ChangeCash(payment * (1f - Cut)) became ChangeCash(payment * (1f - DealerData.SalesCutPercentage)) (Dealer.cs:132, DealerNPCData.cs:17)", Emit = (ModuleDefinition module, TypeDefinition type) => EmitDealerCut(module, type, setter: true) }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.UI.GameplayMenu", OldName = "SetIsOpen", ParameterCount = 1, ParameterTypes = new string[1] { "System.Boolean" }, Because = "0.4.6 split GameplayMenu.SetIsOpen(bool) into Open() and Close(): 0.4.5f2 has SetIsOpen and neither of them, 0.4.6f13 has both and no SetIsOpen (GameplayMenu.cs:238,243)", Emit = EmitGameplayMenuSetIsOpen }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.UI.SleepCanvas", OldName = "SetIsOpen", ParameterCount = 1, ParameterTypes = new string[1] { "System.Boolean" }, Because = "0.4.6 replaced SleepCanvas.SetIsOpen(bool) with OpenMenu() and the menu stack: 0.4.5f2 has SetIsOpen and neither, 0.4.6f13 has OpenMenu, a MenuState field and no SetIsOpen (SleepCanvas.cs:88,92)", Emit = EmitSleepCanvasSetIsOpen }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.PlayerScripts.Player", OldName = "Activate", ParameterCount = 0, Because = "Player.cs:1423-1441 until 0.4.5f2; 0.4.6 deleted both and rewrote its own three callers to register a UI element instead, leaving every line these ran still there", Emit = (ModuleDefinition module, TypeDefinition type) => EmitPlayerToggle(module, type, "Activate", on: true) }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.PlayerScripts.Player", OldName = "Deactivate", ParameterCount = 1, Because = "Player.cs:1423-1441 until 0.4.5f2; 0.4.6 deleted both and rewrote its own three callers to register a UI element instead, leaving every line these ran still there", Emit = (ModuleDefinition module, TypeDefinition type) => EmitPlayerToggle(module, type, "Deactivate", on: false) }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.ObjectScripts.PackagingStation", OldName = "Close", ParameterCount = 0, Because = "0.4.6 renamed PackagingStation.Close() to OnEndUse(): both close the canvas and release the player user, and it is the only zero-argument method on the type that does (PackagingStation.cs:416)", Emit = (ModuleDefinition module, TypeDefinition type) => EmitSelfCall(module, type, "Close", "OnEndUse") }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.PlayerScripts.PlayerCamera", OldName = "CloseInterface", ParameterCount = 2, ParameterTypes = new string[2] { "System.Single", "System.Boolean" }, Because = "0.4.6 deleted PlayerCamera.CloseInterface(float, bool) along with the way screens used to close; every line of its body still exists, so it is rebuilt rather than pointed somewhere (0.4.5f2 PlayerCamera.cs:1157-1169)", Emit = EmitCloseInterface }, Defaulted("Il2CppScheduleOne.PlayerScripts.PlayerCamera", "FreeMouse", NoParameters, new object[1] { true }, "the crosshair became a parameter; true is what the call did before it existed (PlayerCamera.cs:483-490)"), Defaulted("Il2CppScheduleOne.PlayerScripts.PlayerCamera", "LockMouse", NoParameters, new object[1] { true }, "the crosshair became a parameter; true is what the call did before it existed (PlayerCamera.cs:483-490)"), Defaulted("Il2CppScheduleOne.UI.StorageMenu", "Open", new string[3] { "Il2CppScheduleOne.ItemFramework.IItemSlotOwner", "System.String", "System.String" }, OneCallback, "Open took a callback in 0.4.6 and the old three-argument form passed none (StorageMenu.cs:56)"), Defaulted("Il2CppScheduleOne.UI.StorageMenu", "Open", new string[3] { "System.String", "System.String", "Il2CppScheduleOne.ItemFramework.IItemSlotOwner" }, OneCallback, "the same callback, on the overload that names the storage last (StorageMenu.cs:62)"), Defaulted("Il2CppScheduleOne.UI.StorageMenu", "Open", new string[1] { "Il2CppScheduleOne.Storage.StorageEntity" }, OneCallback, "the same callback, on the overload that takes a storage entity (StorageMenu.cs:50)"), new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Tools.ManagementClipboard", OldName = "Close", ParameterCount = 1, AllowOverload = true, Because = "Close(preserveState) became two methods that differ by HOW they close, not by the flag: only the popping one hands the player back their movement, so both values write the flag and pop (ManagementClipboard.cs:103-113, 0.4.5f2 106-120)", Emit = EmitClipboardClose }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Economy.CustomerData", OldName = "GetOrderDays", ParameterCount = 2, AllowOverload = true, Because = "it stopped returning the list and started filling one it is handed (CustomerData.cs:92)", Emit = EmitGetOrderDays }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.UI.App`1", OldName = "Exit", ParameterCount = 1, AllowOverload = true, Because = "ExitAction moved from ScheduleOne.DevUtilities to ScheduleOne; this takes the name the mod knows and hands it to the one method there is", Emit = EmitAppExit }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.GameInput/ExitDelegate", OldName = "op_Implicit", ParameterCount = 1, AllowOverload = true, Because = "an Action of the old ExitAction cannot be an Action of the new one - the conversion goes the wrong way for a delegate - so this wraps it rather than casting it", Emit = EmitExitDelegateConversion }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Economy.Supplier", OldName = "get_meetingGreeting", ParameterCount = 0, Because = "Supplier.cs:186-199 until 0.4.5f2 kept the greeting and the choice in fields; 0.4.6 builds the same two objects as locals in Start() and hands them to the DialogueController, so they are still there and only the way to them is gone", Emit = (ModuleDefinition module, TypeDefinition type) => EmitFromController(module, type, "get_meetingGreeting", "GreetingOverrides", "Greeting", MeetingGreetingLine) }, new Bridge { Assembly = "Assembly-CSharp", DeclaringType = "Il2CppScheduleOne.Economy.Supplier", OldName = "get_meetingChoice", ParameterCount = 0, Because = "Supplier.cs:186-199 until 0.4.5f2 kept the greeting and the choice in fields; 0.4.6 builds the same two objects as locals in Start() and hands them to the DialogueController, so they are still there and only the way to them is gone", Emit = (ModuleDefinition module, TypeDefinition type) => EmitFromController(module, type, "get_meetingChoice", "Choices", "ChoiceText", delegate(ModuleDefinition val, MethodDefinition method, ILProcessor il, Instruction giveUp) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) il.Emit(OpCodes.Ldstr, "Yes"); }) } }; private const string ExitActionOld = "Il2CppScheduleOne.DevUtilities.ExitAction"; private const string Supplier = "Il2CppScheduleOne.Economy.Supplier"; private const string Controller = "Il2CppScheduleOne.Dialogue.DialogueController"; private const string MeetingWhy = "Supplier.cs:186-199 until 0.4.5f2 kept the greeting and the choice in fields; 0.4.6 builds the same two objects as locals in Start() and hands them to the DialogueController, so they are still there and only the way to them is gone"; internal override string Step => "0.4.5f2 -> 0.4.6f5"; internal override string From => "0.4.6f5"; internal override string VerifiedTo => "0.4.6f13"; private static FieldDefinition Slot(ModuleDefinition module, TypeDefinition facade) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown Enumerator enumerator = facade.Fields.GetEnumerator(); try { while (enumerator.MoveNext()) { FieldDefinition current = enumerator.Current; if (((MemberReference)current).Name == "polyfillLoadedModule") { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } FieldDefinition val = new FieldDefinition("polyfillLoadedModule", (FieldAttributes)17, module.TypeSystem.String); facade.Fields.Add(val); return val; } private static MethodDefinition TakingOneString(TypeDefinition type, string name) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Invalid comparison between Unknown and I4 if (type == null) { return null; } MethodDefinition val = null; Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (!(((MemberReference)current).Name != name) && ((MethodReference)current).Parameters.Count == 1 && (int)((ParameterReference)((MethodReference)current).Parameters[0]).ParameterType.MetadataType == 14) { if (val != null) { return null; } val = current; } } return val; } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } private static void PushManager(ILProcessor il, MethodReference pointer, MethodReference make) { //IL_0001: 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) //IL_0018: Unknown result type (might be due to invalid IL or missing references) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, pointer); il.Emit(OpCodes.Newobj, make); } private static MethodDefinition EmitLoadModule(ModuleDefinition module, TypeDefinition facade, TypeDefinition manager) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown MethodDefinition val = TakingOneString(manager, "LoadModule"); MethodDefinition val2 = TakingOneString(manager, "UnloadModule"); MethodDefinition val3 = ShadowTypes.PointerGetter(manager); MethodDefinition val4 = ShadowTypes.PointerConstructorOf(manager); if (val == null || val2 == null || val3 == null || val4 == null) { return null; } FieldDefinition val5 = Slot(module, facade); MethodDefinition val6 = new MethodDefinition("LoadModule", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val6).Parameters.Add(new ParameterDefinition("key", (ParameterAttributes)0, module.TypeSystem.String)); ILProcessor iLProcessor = val6.Body.GetILProcessor(); Instruction val7 = iLProcessor.Create(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val5); iLProcessor.Emit(OpCodes.Brfalse, val7); PushManager(iLProcessor, module.ImportReference((MethodReference)(object)val3), module.ImportReference((MethodReference)(object)val4)); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val5); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Append(val7); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Newobj, module.ImportReference((MethodReference)(object)val4)); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Stsfld, (FieldReference)(object)val5); iLProcessor.Emit(OpCodes.Ret); return val6; } private static MethodDefinition EmitUnloadModule(ModuleDefinition module, TypeDefinition facade, TypeDefinition manager) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown MethodDefinition val = TakingOneString(manager, "UnloadModule"); MethodDefinition val2 = ShadowTypes.PointerGetter(manager); MethodDefinition val3 = ShadowTypes.PointerConstructorOf(manager); if (val == null || val2 == null || val3 == null) { return null; } FieldDefinition val4 = Slot(module, facade); MethodDefinition val5 = new MethodDefinition("UnloadModule", (MethodAttributes)134, module.TypeSystem.Void); ILProcessor iLProcessor = val5.Body.GetILProcessor(); Instruction val6 = iLProcessor.Create(OpCodes.Ret); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val4); iLProcessor.Emit(OpCodes.Brfalse, val6); PushManager(iLProcessor, module.ImportReference((MethodReference)(object)val2), module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val4); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ldnull); iLProcessor.Emit(OpCodes.Stsfld, (FieldReference)(object)val4); iLProcessor.Append(val6); return val5; } private static MethodDefinition EmitCurrentModuleLabel(ModuleDefinition module, TypeDefinition facade, TypeDefinition manager) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown MethodDefinition val = TakingOneString(manager, "HasActivePrompt"); MethodDefinition val2 = ShadowTypes.PointerGetter(manager); MethodDefinition val3 = ShadowTypes.PointerConstructorOf(manager); if (val == null || (int)((MethodReference)val).ReturnType.MetadataType != 2 || val2 == null || val3 == null) { return null; } FieldDefinition val4 = Slot(module, facade); MethodDefinition val5 = new MethodDefinition("get_currentModuleLabel", (MethodAttributes)2182, module.TypeSystem.String); ILProcessor iLProcessor = val5.Body.GetILProcessor(); Instruction val6 = iLProcessor.Create(OpCodes.Ldstr, ""); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val4); iLProcessor.Emit(OpCodes.Brfalse, val6); PushManager(iLProcessor, module.ImportReference((MethodReference)(object)val2), module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val4); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Brfalse, val6); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val4); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val6); iLProcessor.Emit(OpCodes.Ret); return val5; } internal override IEnumerable Declare() { return All; } internal override IEnumerable DeclareRenames() { return Renamed_; } private static Bridge Unprompted(Bridge bridge) { bridge.Unprompted = true; return bridge; } private static TypeRename Pair(string oldFullName, string newFullName) { return new TypeRename { Assembly = "Assembly-CSharp", OldFullName = oldFullName, NewFullName = newFullName, Because = "0.4.6 factored the station screens onto a shared StationInterface base and renamed the four that still said Canvas; same members, same namespace, one word different" }; } private static MethodDefinition EmitMovementSpeedScaleGetter(ModuleDefinition module, TypeDefinition movement) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown MethodDefinition val = Getter(movement, "SpeedController"); object type; if (val == null) { type = null; } else { TypeReference returnType = ((MethodReference)val).ReturnType; type = ((returnType != null) ? returnType.Resolve() : null); } MethodDefinition val2 = Getter((TypeDefinition)type, "ActiveSpeedControl"); MethodDefinition val3 = Getter((TypeDefinition)type, "SpeedMultiplier"); object type2; if (val2 == null) { type2 = null; } else { TypeReference returnType2 = ((MethodReference)val2).ReturnType; type2 = ((returnType2 != null) ? returnType2.Resolve() : null); } MethodDefinition val4 = Getter((TypeDefinition)type2, "speed"); if (val == null || val2 == null || val3 == null || val4 == null) { return null; } MethodDefinition val5 = new MethodDefinition("get_MovementSpeedScale", (MethodAttributes)134, module.TypeSystem.Single); ILProcessor iLProcessor = val5.Body.GetILProcessor(); Instruction val6 = iLProcessor.Create(OpCodes.Ldc_R4, 0f); Instruction val7 = iLProcessor.Create(OpCodes.Nop); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, (MethodReference)(object)val); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brtrue_S, val7); iLProcessor.Emit(OpCodes.Pop); iLProcessor.Append(val6); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val7); iLProcessor.Emit(OpCodes.Callvirt, (MethodReference)(object)val2); Instruction val8 = iLProcessor.Create(OpCodes.Callvirt, (MethodReference)(object)val4); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brtrue_S, val8); iLProcessor.Emit(OpCodes.Pop); iLProcessor.Emit(OpCodes.Ldc_R4, 0f); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val8); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, (MethodReference)(object)val); iLProcessor.Emit(OpCodes.Callvirt, (MethodReference)(object)val3); iLProcessor.Emit(OpCodes.Mul); iLProcessor.Emit(OpCodes.Ret); return val5; } private static MethodDefinition EmitMovementSpeedScaleSetter(ModuleDefinition module, TypeDefinition movement) { //IL_0077: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown MethodDefinition val = Getter(movement, "SpeedController"); object type; if (val == null) { type = null; } else { TypeReference returnType = ((MethodReference)val).ReturnType; type = ((returnType != null) ? returnType.Resolve() : null); } MethodDefinition val2 = Method((TypeDefinition)type, "AddSpeedControl", 1); MethodDefinition val3 = Method((TypeDefinition)type, "RemoveSpeedControl", 1); MethodDefinition val4 = Method(Nested((TypeDefinition)type, "SpeedControl"), ".ctor", 3); if (val == null || val2 == null || val3 == null || val4 == null) { return null; } MethodDefinition val5 = new MethodDefinition("set_MovementSpeedScale", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val5).Parameters.Add(new ParameterDefinition("value", (ParameterAttributes)0, module.TypeSystem.Single)); ILProcessor iLProcessor = val5.Body.GetILProcessor(); Instruction val6 = iLProcessor.Create(OpCodes.Ret); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, (MethodReference)(object)val); iLProcessor.Emit(OpCodes.Dup); Instruction val7 = iLProcessor.Create(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brtrue_S, val7); iLProcessor.Emit(OpCodes.Pop); iLProcessor.Emit(OpCodes.Br_S, val6); iLProcessor.Append(val7); iLProcessor.Emit(OpCodes.Ldstr, "Polyfill"); iLProcessor.Emit(OpCodes.Callvirt, (MethodReference)(object)val3); iLProcessor.Emit(OpCodes.Ldstr, "Polyfill"); iLProcessor.Emit(OpCodes.Ldc_I4_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Newobj, (MethodReference)(object)val4); iLProcessor.Emit(OpCodes.Callvirt, (MethodReference)(object)val2); iLProcessor.Append(val6); return val5; } private static MethodDefinition EmitOverrideAggression(ModuleDefinition module, TypeDefinition npc) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown MethodDefinition val = Getter(npc, "AggressionController"); object type; if (val == null) { type = null; } else { TypeReference returnType = ((MethodReference)val).ReturnType; type = ((returnType != null) ? returnType.Resolve() : null); } MethodDefinition val2 = Method((TypeDefinition)type, "Add", 1); TypeDefinition type2 = Nested((TypeDefinition)type, "StackEntry"); TypeDefinition val3 = Nested((TypeDefinition)type, "EStackMode"); MethodDefinition val4 = Method(type2, ".ctor", 4); if (val == null || val2 == null || val4 == null || val3 == null) { return null; } MethodDefinition val5 = new MethodDefinition("OverrideAggression", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val5).Parameters.Add(new ParameterDefinition("aggression", (ParameterAttributes)0, module.TypeSystem.Single)); ILProcessor iLProcessor = val5.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, (MethodReference)(object)val); iLProcessor.Emit(OpCodes.Ldstr, "Polyfill"); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Ldc_I4_0); iLProcessor.Emit(OpCodes.Newobj, (MethodReference)(object)val4); iLProcessor.Emit(OpCodes.Callvirt, (MethodReference)(object)val2); iLProcessor.Emit(OpCodes.Ret); return val5; } private static Bridge Moved(string declaringType, string oldName, bool write, string[] hops, string target, string because) { string accessor = (write ? "set_" : "get_") + oldName; return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = accessor, ParameterCount = (write ? 1 : 0), Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitThrough(module, type, accessor, hops, target, write) }; } private static MethodDefinition EmitThrough(ModuleDefinition module, TypeDefinition owner, string accessor, string[] hops, string target, bool write) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) List list = new List(); TypeDefinition val = owner; foreach (string member in hops) { MethodDefinition val2 = Getter(val, member); if (val2 == null) { return null; } list.Add(val2); TypeReference returnType = ((MethodReference)val2).ReturnType; val = ((returnType != null) ? returnType.Resolve() : null); if (val == null) { return null; } } MethodDefinition val3 = (write ? Method(val, "set_" + target, 1) : Getter(val, target)); if (val3 == null) { return null; } TypeReference val4 = (write ? ((ParameterReference)((MethodReference)val3).Parameters[0]).ParameterType : ((MethodReference)val3).ReturnType); TypeReference val5 = (write ? module.TypeSystem.Void : module.ImportReference(val4)); MethodDefinition val6 = new MethodDefinition(accessor, (MethodAttributes)134, val5); if (write) { ((MethodReference)val6).Parameters.Add(new ParameterDefinition("value", (ParameterAttributes)0, module.ImportReference(val4))); } ILProcessor iLProcessor = val6.Body.GetILProcessor(); Instruction val7 = iLProcessor.Create(OpCodes.Nop); iLProcessor.Emit(OpCodes.Ldarg_0); for (int j = 0; j < list.Count; j++) { iLProcessor.Emit((j == 0) ? OpCodes.Call : OpCodes.Callvirt, module.ImportReference((MethodReference)(object)list[j])); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brfalse, val7); } if (write) { iLProcessor.Emit(OpCodes.Ldarg_1); } iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val7); iLProcessor.Emit(OpCodes.Pop); if (!write) { EmitDefault(val6, iLProcessor, val5); } iLProcessor.Emit(OpCodes.Ret); val6.Body.InitLocals = true; return val6; } private static Bridge Elsewhere(string declaringType, string name, string[] parameters, string nowOn, string because, string nowCalled = null) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = name, ParameterCount = parameters.Length, ParameterTypes = parameters, AllowOverload = true, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitElsewhere(module, type, name, parameters, nowOn, nowCalled ?? name) }; } private static Bridge ElsewhereByShape(string declaringType, string name, int parameterCount, string nowOn, string because, Func pick) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = name, ParameterCount = parameterCount, AllowOverload = true, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitPicked(module, type, name, parameterCount, nowOn, pick) }; } private static MethodDefinition EmitPicked(ModuleDefinition module, TypeDefinition owner, string name, int parameterCount, string nowOn, Func pick) { //IL_0016: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) TypeDefinition type = module.GetType(nowOn); if (type == null) { return null; } MethodDefinition val = null; Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name != name || !current.IsStatic || ((MethodReference)current).Parameters.Count != parameterCount) { continue; } bool flag; try { flag = pick(current); } catch { return null; } if (flag) { if (val != null) { return null; } val = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null || ((MethodReference)val).HasGenericParameters) { return null; } MethodDefinition val2 = new MethodDefinition(name, (MethodAttributes)150, module.ImportReference(((MethodReference)val).ReturnType)); Enumerator enumerator2 = ((MethodReference)val).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current2 = enumerator2.Current; ((MethodReference)val2).Parameters.Add(new ParameterDefinition(((ParameterReference)current2).Name, (ParameterAttributes)0, module.ImportReference(((ParameterReference)current2).ParameterType))); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } ILProcessor iLProcessor = val2.Body.GetILProcessor(); enumerator2 = ((MethodReference)val2).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current3 = enumerator2.Current; iLProcessor.Emit(OpCodes.Ldarg, current3); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static Bridge ElsewhereStatic(string declaringType, string oldName, int oldParameterCount, string nowOn, string because, object[] defaults = null) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = oldName, ParameterCount = oldParameterCount, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitElsewhereStatic(module, oldName, oldParameterCount, nowOn, defaults ?? Array.Empty()) }; } private static MethodDefinition EmitElsewhereStatic(ModuleDefinition module, string name, int oldParameterCount, string nowOn, object[] defaults) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Invalid comparison between Unknown and I4 //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Invalid comparison between Unknown and I4 //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) TypeDefinition type = module.GetType(nowOn); if (type == null) { return null; } int num = oldParameterCount + defaults.Length; MethodDefinition val = null; Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (!(((MemberReference)current).Name != name) && current.IsStatic && ((MethodReference)current).Parameters.Count == num) { if (val != null) { return null; } val = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null || ((MethodReference)val).HasGenericParameters) { return null; } MethodDefinition val2 = new MethodDefinition(name, (MethodAttributes)134, module.ImportReference(((MethodReference)val).ReturnType)); for (int i = 0; i < oldParameterCount; i++) { ((MethodReference)val2).Parameters.Add(new ParameterDefinition(((ParameterReference)((MethodReference)val).Parameters[i]).Name, (ParameterAttributes)0, module.ImportReference(((ParameterReference)((MethodReference)val).Parameters[i]).ParameterType))); } ILProcessor iLProcessor = val2.Body.GetILProcessor(); Enumerator enumerator2 = ((MethodReference)val2).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current2 = enumerator2.Current; iLProcessor.Emit(OpCodes.Ldarg, current2); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } for (int j = 0; j < defaults.Length; j++) { TypeReference parameterType = ((ParameterReference)((MethodReference)val).Parameters[oldParameterCount + j]).ParameterType; if (defaults[j] is bool flag && (int)parameterType.MetadataType == 2) { iLProcessor.Emit(flag ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); continue; } if (defaults[j] is int num2 && (int)parameterType.MetadataType == 8) { iLProcessor.Emit(OpCodes.Ldc_I4, num2); continue; } return null; } iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static MethodDefinition EmitElsewhere(ModuleDefinition module, TypeDefinition owner, string name, string[] parameters, string nowOn, string nowCalled) { //IL_0016: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) TypeDefinition type = module.GetType(nowOn); if (type == null) { return null; } MethodDefinition val = null; Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name != nowCalled || !current.IsStatic || ((MethodReference)current).Parameters.Count != parameters.Length) { continue; } bool flag = true; for (int i = 0; i < parameters.Length; i++) { if (((MemberReference)((ParameterReference)((MethodReference)current).Parameters[i]).ParameterType).FullName != parameters[i]) { flag = false; break; } } if (flag) { if (val != null) { return null; } val = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null || ((MethodReference)val).HasGenericParameters) { return null; } MethodDefinition val2 = new MethodDefinition(name, (MethodAttributes)150, module.ImportReference(((MethodReference)val).ReturnType)); Enumerator enumerator2 = ((MethodReference)val).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current2 = enumerator2.Current; ((MethodReference)val2).Parameters.Add(new ParameterDefinition(((ParameterReference)current2).Name, (ParameterAttributes)0, module.ImportReference(((ParameterReference)current2).ParameterType))); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } ILProcessor iLProcessor = val2.Body.GetILProcessor(); enumerator2 = ((MethodReference)val2).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current3 = enumerator2.Current; iLProcessor.Emit(OpCodes.Ldarg, current3); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static Bridge Onto(string declaringType, string oldName, int parameterCount, string[] hops, string target, string because, string[] keptArgumentNames = null) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = oldName, ParameterCount = parameterCount, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitOnto(module, type, oldName, hops, target, parameterCount, keptArgumentNames) }; } private static MethodDefinition EmitOnto(ModuleDefinition module, TypeDefinition owner, string oldName, string[] hops, string target, int parameterCount, string[] keptArgumentNames = null) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) List list = new List(); TypeDefinition val = owner; foreach (string member in hops) { MethodDefinition val2 = Getter(val, member); if (val2 == null) { return null; } list.Add(val2); TypeReference returnType = ((MethodReference)val2).ReturnType; val = ((returnType != null) ? returnType.Resolve() : null); if (val == null) { return null; } } MethodDefinition val3 = MethodUp(val, target, parameterCount); if (val3 == null || ((MethodReference)val3).HasGenericParameters) { return null; } MethodDefinition val4 = new MethodDefinition(oldName, (MethodAttributes)134, module.ImportReference(((MethodReference)val3).ReturnType)); for (int j = 0; j < ((MethodReference)val3).Parameters.Count; j++) { ParameterDefinition val5 = ((MethodReference)val3).Parameters[j]; string text = ((keptArgumentNames != null && j < keptArgumentNames.Length) ? keptArgumentNames[j] : ((ParameterReference)val5).Name); ((MethodReference)val4).Parameters.Add(new ParameterDefinition(text, (ParameterAttributes)0, module.ImportReference(((ParameterReference)val5).ParameterType))); } ILProcessor iLProcessor = val4.Body.GetILProcessor(); Instruction val6 = iLProcessor.Create(OpCodes.Nop); iLProcessor.Emit(OpCodes.Ldarg_0); for (int k = 0; k < list.Count; k++) { iLProcessor.Emit((k == 0) ? OpCodes.Call : OpCodes.Callvirt, module.ImportReference((MethodReference)(object)list[k])); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brfalse, val6); } Enumerator enumerator = ((MethodReference)val4).Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; iLProcessor.Emit(OpCodes.Ldarg, current); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val6); iLProcessor.Emit(OpCodes.Pop); if (((MemberReference)((MethodReference)val4).ReturnType).FullName != "System.Void") { EmitDefault(val4, iLProcessor, ((MethodReference)val4).ReturnType); } iLProcessor.Emit(OpCodes.Ret); val4.Body.InitLocals = true; return val4; } private static Bridge NowCalled(string declaringType, string oldName, int parameterCount, string newName, string because, string[] keptArgumentNames = null) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = oldName, ParameterCount = parameterCount, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitCall(module, type, oldName, newName, parameterCount, keptArgumentNames) }; } private static Bridge Defaulted(string declaringType, string name, string[] leading, object[] defaults, string because) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = name, ParameterCount = leading.Length, ParameterTypes = leading, AllowOverload = true, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitWithDefaults(module, type, name, leading, defaults) }; } private static MethodDefinition EmitPlayerToggle(ModuleDefinition module, TypeDefinition player, string name, bool on) { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) (TypeDefinition, MethodReference) tuple = Singleton(module, "Il2CppScheduleOne.PlayerScripts.PlayerCamera", player: true); (TypeDefinition, MethodReference) tuple2 = Singleton(module, "Il2CppScheduleOne.PlayerScripts.PlayerMovement", player: true); (TypeDefinition, MethodReference) tuple3 = Singleton(module, "Il2CppScheduleOne.PlayerScripts.PlayerInventory", player: true); (TypeDefinition, MethodReference) tuple4 = Singleton(module, "Il2CppScheduleOne.UI.HUD", player: false); if (tuple.Item2 == null || tuple2.Item2 == null || tuple3.Item2 == null || tuple4.Item2 == null) { return null; } MethodDefinition val = Method(tuple.Item1, "SetCanLook", 1); MethodDefinition val2 = Method(tuple2.Item1, "set_CanMove", 1); MethodDefinition val3 = Method(tuple3.Item1, "SetInventoryEnabled", 1); MethodDefinition val4 = Method(tuple4.Item1, "SetCrosshairVisible", 1); MethodDefinition val5 = Method(tuple.Item1, on ? "LockMouse" : "FreeMouse", 1); MethodDefinition val6 = Method(tuple.Item1, "ResetRotation", 0); if (val == null || val2 == null || val3 == null || val4 == null || val5 == null || (!on && val6 == null)) { return null; } MethodDefinition val7 = new MethodDefinition(name, (MethodAttributes)150, module.TypeSystem.Void); if (!on) { ((MethodReference)val7).Parameters.Add(new ParameterDefinition("freeMouse", (ParameterAttributes)0, module.TypeSystem.Boolean)); } ILProcessor iLProcessor = val7.Body.GetILProcessor(); OpCode val8 = (on ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); iLProcessor.Emit(OpCodes.Call, tuple.Item2); iLProcessor.Emit(val8); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); if (!on) { iLProcessor.Emit(OpCodes.Call, tuple.Item2); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val6)); } iLProcessor.Emit(OpCodes.Call, tuple2.Item2); iLProcessor.Emit(val8); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Call, tuple3.Item2); iLProcessor.Emit(val8); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); if (on) { iLProcessor.Emit(OpCodes.Call, tuple4.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val4)); iLProcessor.Emit(OpCodes.Call, tuple.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val5)); iLProcessor.Emit(OpCodes.Ret); return val7; } Instruction val9 = iLProcessor.Create(OpCodes.Ret); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Brfalse, val9); iLProcessor.Emit(OpCodes.Call, tuple.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val5)); iLProcessor.Append(val9); return val7; } private static MethodDefinition EmitSelfCall(ModuleDefinition module, TypeDefinition type, string oldName, string newName) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown MethodDefinition val = MethodUp(type, newName, 0); if (val == null) { return null; } MethodDefinition val2 = new MethodDefinition(oldName, (MethodAttributes)134, module.ImportReference(((MethodReference)val).ReturnType)); ILProcessor iLProcessor = val2.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static MethodDefinition EmitCloseInterface(ModuleDefinition module, TypeDefinition camera) { //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) (TypeDefinition, MethodReference) tuple = Singleton(module, "Il2CppScheduleOne.UI.HUD", player: false); (TypeDefinition, MethodReference) tuple2 = Singleton(module, "Il2CppScheduleOne.PlayerScripts.PlayerMovement", player: true); (TypeDefinition, MethodReference) tuple3 = Singleton(module, "Il2CppScheduleOne.UI.Compass.CompassManager", player: false); (TypeDefinition, MethodReference) tuple4 = Singleton(module, "Il2CppScheduleOne.PlayerScripts.PlayerInventory", player: true); (TypeDefinition, MethodReference) tuple5 = Singleton(module, "Il2CppScheduleOne.UI.Items.ItemUIManager", player: false); if (tuple.Item2 == null || tuple2.Item2 == null || tuple3.Item2 == null || tuple4.Item2 == null || tuple5.Item2 == null) { return null; } MethodDefinition val = MethodUp(camera, "LockMouse", 1) ?? MethodUp(camera, "LockMouse", 0); MethodDefinition val2 = Method(tuple.Item1, "SetCrosshairVisible", 1); MethodDefinition val3 = Method(tuple2.Item1, "set_CanMove", 1); MethodDefinition val4 = Method(tuple3.Item1, "SetCompassEnabled", 1); MethodDefinition val5 = Method(tuple4.Item1, "SetInventoryEnabled", 1); MethodDefinition val6 = Method(tuple4.Item1, "SetEquippingEnabled", 1); MethodDefinition val7 = Method(tuple5.Item1, "SetDraggingEnabled", 1); MethodDefinition val8 = Method(tuple5.Item1, "DisableQuickMove", 0); MethodDefinition val9 = MethodUp(camera, "StopFOVOverride", 1); MethodDefinition val10 = MethodUp(camera, "StopTransformOverride", 2) ?? MethodUp(camera, "StopTransformOverride", 3); if (val == null || val2 == null || val3 == null || val4 == null || val5 == null || val6 == null || val7 == null || val8 == null || val9 == null || val10 == null) { return null; } MethodDefinition val11 = new MethodDefinition("CloseInterface", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val11).Parameters.Add(new ParameterDefinition("cameraLerpTime", (ParameterAttributes)0, module.TypeSystem.Single)); ((MethodReference)val11).Parameters.Add(new ParameterDefinition("reenableCameraInput", (ParameterAttributes)0, module.TypeSystem.Boolean)); ILProcessor iLProcessor = val11.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); for (int i = 0; i < ((MethodReference)val).Parameters.Count; i++) { iLProcessor.Emit(OpCodes.Ldc_I4_1); } iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Call, tuple.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Call, tuple2.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Call, tuple3.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val4)); iLProcessor.Emit(OpCodes.Call, tuple4.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val5)); iLProcessor.Emit(OpCodes.Call, tuple4.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val6)); iLProcessor.Emit(OpCodes.Call, tuple5.Item2); iLProcessor.Emit(OpCodes.Ldc_I4_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val7)); iLProcessor.Emit(OpCodes.Call, tuple5.Item2); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val8)); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val9)); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Ldarg_2); for (int j = 2; j < ((MethodReference)val10).Parameters.Count; j++) { iLProcessor.Emit(OpCodes.Ldc_I4_1); } iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val10)); iLProcessor.Emit(OpCodes.Ret); return val11; } private static (TypeDefinition Type, MethodReference Get) Singleton(ModuleDefinition module, string fullName, bool player) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown TypeDefinition type = module.GetType(fullName); if (type == null) { return (Type: null, Get: null); } string text = "Il2CppScheduleOne.DevUtilities." + (player ? "PlayerSingleton`1" : "Singleton`1"); TypeDefinition type2 = module.GetType(text); MethodDefinition val = Method(type2, "get_Instance", 0); if (val == null || !val.IsStatic) { return (Type: type, Get: null); } GenericInstanceType val2 = new GenericInstanceType(module.ImportReference((TypeReference)(object)type2)); val2.GenericArguments.Add(module.ImportReference((TypeReference)(object)type)); return (Type: type, Get: Against(module, val, (TypeReference)(object)val2)); } private static Bridge SplitInTwo(int index) { SplitScreens.Entry entry = SplitScreens.All[index]; string[] array = ((!entry.HasRemoveUi) ? new string[2] { entry.Station, "System.Boolean" } : new string[3] { entry.Station, "System.Boolean", "System.Boolean" }); return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = entry.Type, OldName = "SetIsOpen", ParameterCount = array.Length, ParameterTypes = array, AllowOverload = true, Because = "0.4.6 split SetIsOpen into Open and Close; this is where a patch aimed at the old name lands, and Polyfill calls it from both of them", Emit = (ModuleDefinition module, TypeDefinition type) => EmitSplitHook(module, type, entry) }; } private static MethodDefinition EmitGameplayMenuSetIsOpen(ModuleDefinition module, TypeDefinition type) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown MethodDefinition val = MethodUp(type, "Open", 0); MethodDefinition val2 = MethodUp(type, "Close", 0); if (val == null || val2 == null) { return null; } MethodDefinition val3 = new MethodDefinition("SetIsOpen", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val3).Parameters.Add(new ParameterDefinition("open", (ParameterAttributes)0, module.TypeSystem.Boolean)); ILProcessor iLProcessor = val3.Body.GetILProcessor(); Instruction val4 = iLProcessor.Create(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Brfalse_S, val4); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val4); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Ret); return val3; } private static MethodDefinition EmitSleepCanvasSetIsOpen(ModuleDefinition module, TypeDefinition type) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown MethodDefinition val = MethodUp(type, "OpenMenu", 0); if (val == null) { return null; } MethodDefinition val2 = MethodUp(type, "get_MenuState", 0); if (val2 == null) { return null; } TypeDefinition val3 = null; try { TypeReference returnType = ((MethodReference)val2).ReturnType; val3 = ((returnType != null) ? returnType.Resolve() : null); } catch { } MethodDefinition val4 = ((val3 == null) ? null : MethodUp(val3, "PopFromDefaultParent", 0)); if (val4 == null) { return null; } MethodDefinition val5 = new MethodDefinition("SetIsOpen", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val5).Parameters.Add(new ParameterDefinition("open", (ParameterAttributes)0, module.TypeSystem.Boolean)); ILProcessor iLProcessor = val5.Body.GetILProcessor(); Instruction val6 = iLProcessor.Create(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Brfalse_S, val6); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val6); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val4)); iLProcessor.Emit(OpCodes.Ret); return val5; } private static Bridge ReplacedByTwo(int index) { ReplacedMethods.Entry entry = ReplacedMethods.All[index]; return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = entry.Type, OldName = entry.OldName, ParameterCount = entry.Parameters.Length, ParameterTypes = entry.Parameters, AllowOverload = true, Because = entry.Because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitReplacedHook(module, type, entry) }; } private static MethodDefinition EmitReplacedHook(ModuleDefinition module, TypeDefinition type, ReplacedMethods.Entry entry) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown ReplacedMethods.Replacement[] replacements = entry.Replacements; foreach (ReplacedMethods.Replacement replacement in replacements) { if (MethodUp(type, replacement.Name, replacement.Parameters.Length) == null) { return null; } } MethodDefinition val = new MethodDefinition(entry.OldName, (MethodAttributes)134, module.TypeSystem.Void); for (int j = 0; j < entry.Parameters.Length; j++) { TypeDefinition type2 = module.GetType(entry.Parameters[j]); TypeReference val2 = ((type2 != null) ? module.ImportReference((TypeReference)(object)type2) : Named(module, entry.Parameters[j])); if (val2 == null) { return null; } ((MethodReference)val).Parameters.Add(new ParameterDefinition(entry.ParameterNames[j], (ParameterAttributes)0, val2)); } val.Body.GetILProcessor().Emit(OpCodes.Ret); return val; } private static TypeReference Named(ModuleDefinition module, string fullName) { return (TypeReference)(fullName switch { "System.Boolean" => module.TypeSystem.Boolean, "System.Int32" => module.TypeSystem.Int32, "System.Single" => module.TypeSystem.Single, "System.String" => module.TypeSystem.String, _ => null, }); } private static MethodDefinition EmitDealerCut(ModuleDefinition module, TypeDefinition type, bool setter) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) TypeDefinition type2 = module.GetType("Il2CppScheduleOne.NPCs.Framework.DealerNPCData"); MethodDefinition val = MethodUp(type, "get_DealerData", 0); if (type2 == null || val == null) { return null; } MethodDefinition val2 = MethodUp(type2, setter ? "set_SalesCutPercentage" : "get_SalesCutPercentage", setter ? 1 : 0); if (val2 == null) { return null; } MethodDefinition val3 = new MethodDefinition(setter ? "set_Cut" : "get_Cut", (MethodAttributes)134, setter ? module.TypeSystem.Void : module.TypeSystem.Single); if (setter) { ((MethodReference)val3).Parameters.Add(new ParameterDefinition("value", (ParameterAttributes)0, module.TypeSystem.Single)); } ILProcessor iLProcessor = val3.Body.GetILProcessor(); MethodReference val4 = module.ImportReference((MethodReference)(object)val2); Instruction val5 = (setter ? iLProcessor.Create(OpCodes.Ldarg_1) : iLProcessor.Create(OpCodes.Callvirt, val4)); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brtrue_S, val5); iLProcessor.Emit(OpCodes.Pop); if (!setter) { iLProcessor.Emit(OpCodes.Ldc_R4, 0f); } iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val5); if (setter) { iLProcessor.Emit(OpCodes.Callvirt, val4); } iLProcessor.Emit(OpCodes.Ret); return val3; } private static MethodDefinition EmitSplitHook(ModuleDefinition module, TypeDefinition type, SplitScreens.Entry entry) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown TypeDefinition type2 = module.GetType(entry.Station); if (type2 == null) { return null; } if (MethodUp(type, "Open", 1) == null || MethodUp(type, "Close", 0) == null) { return null; } MethodDefinition val = new MethodDefinition("SetIsOpen", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val).Parameters.Add(new ParameterDefinition(entry.StationName, (ParameterAttributes)0, module.ImportReference((TypeReference)(object)type2))); ((MethodReference)val).Parameters.Add(new ParameterDefinition("open", (ParameterAttributes)0, module.TypeSystem.Boolean)); if (entry.HasRemoveUi) { ((MethodReference)val).Parameters.Add(new ParameterDefinition("removeUI", (ParameterAttributes)0, module.TypeSystem.Boolean)); } val.Body.GetILProcessor().Emit(OpCodes.Ret); return val; } private static MethodDefinition EmitForgottenSetter(ModuleDefinition module, TypeDefinition type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { if (((MemberReference)enumerator.Current).Name == "set_InitialAvatarSettings") { return null; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } TypeDefinition type2 = module.GetType("Il2CppScheduleOne.AvatarFramework.AvatarSettings"); if (type2 == null) { return null; } MethodDefinition val = new MethodDefinition("set_InitialAvatarSettings", (MethodAttributes)2182, module.TypeSystem.Void); ((MethodReference)val).Parameters.Add(new ParameterDefinition("value", (ParameterAttributes)0, module.ImportReference((TypeReference)(object)type2))); val.Body.GetILProcessor().Emit(OpCodes.Ret); type.Properties.Add(new PropertyDefinition("InitialAvatarSettings", (PropertyAttributes)0, module.ImportReference((TypeReference)(object)type2)) { SetMethod = val }); return val; } private static Bridge Dropped(string declaringType, string name, string[] kept, string dropped, string because) { string[] array = new string[kept.Length + 1]; Array.Copy(kept, array, kept.Length); array[kept.Length] = dropped; return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = name, ParameterCount = array.Length, ParameterTypes = array, AllowOverload = true, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitWithoutTrailing(module, type, name, kept, dropped) }; } private static MethodDefinition EmitWithoutTrailing(ModuleDefinition module, TypeDefinition type, string name, string[] kept, string dropped) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = null; Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name != name || ((MethodReference)current).Parameters.Count != kept.Length) { continue; } bool flag = true; for (int i = 0; i < kept.Length; i++) { if (((MemberReference)((ParameterReference)((MethodReference)current).Parameters[i]).ParameterType).FullName != kept[i]) { flag = false; break; } } if (flag) { if (val != null) { return null; } val = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null || ((MethodReference)val).HasGenericParameters) { return null; } TypeReference val2 = (TypeReference)(((object)module.GetType(dropped)) ?? ((object)Find(module, dropped))); if (val2 == null) { return null; } MethodDefinition val3 = new MethodDefinition(name, (MethodAttributes)(0x86 | (val.IsStatic ? 16 : 0)), module.ImportReference(((MethodReference)val).ReturnType)); Enumerator enumerator2 = ((MethodReference)val).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current2 = enumerator2.Current; ((MethodReference)val3).Parameters.Add(new ParameterDefinition(((ParameterReference)current2).Name, (ParameterAttributes)0, module.ImportReference(((ParameterReference)current2).ParameterType))); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } ((MethodReference)val3).Parameters.Add(new ParameterDefinition("dropped", (ParameterAttributes)0, module.ImportReference(val2))); ILProcessor iLProcessor = val3.Body.GetILProcessor(); if (!val.IsStatic) { iLProcessor.Emit(OpCodes.Ldarg_0); } for (int j = 0; j < kept.Length; j++) { iLProcessor.Emit(OpCodes.Ldarg, ((MethodReference)val3).Parameters[j]); } iLProcessor.Emit(val.IsStatic ? OpCodes.Call : OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val3; } private static TypeReference Find(ModuleDefinition module, string fullName) { return (TypeReference)(fullName switch { "System.Boolean" => module.TypeSystem.Boolean, "System.Single" => module.TypeSystem.Single, "System.Int32" => module.TypeSystem.Int32, "System.String" => module.TypeSystem.String, _ => null, }); } private static Bridge NowStatic(string declaringType, string oldName, int parameterCount, string newName, string because) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = oldName, ParameterCount = parameterCount, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitFromStatic(module, type, oldName, newName, parameterCount) }; } private static MethodDefinition EmitFromStatic(ModuleDefinition module, TypeDefinition type, string oldName, string newName, int parameterCount) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = Method(type, newName, parameterCount); if (val == null || !val.IsStatic || ((MethodReference)val).HasGenericParameters) { return null; } MethodDefinition val2 = new MethodDefinition(oldName, (MethodAttributes)2182, module.ImportReference(((MethodReference)val).ReturnType)); Enumerator enumerator = ((MethodReference)val).Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; ((MethodReference)val2).Parameters.Add(new ParameterDefinition(((ParameterReference)current).Name, (ParameterAttributes)0, module.ImportReference(((ParameterReference)current).ParameterType))); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } ILProcessor iLProcessor = val2.Body.GetILProcessor(); enumerator = ((MethodReference)val2).Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current2 = enumerator.Current; iLProcessor.Emit(OpCodes.Ldarg, current2); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static MethodDefinition EmitCall(ModuleDefinition module, TypeDefinition type, string oldName, string newName, int parameterCount, string[] keptArgumentNames = null) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = Method(type, newName, parameterCount); if (val == null || ((MethodReference)val).HasGenericParameters) { return null; } MethodDefinition val2 = new MethodDefinition(oldName, (MethodAttributes)(0x86 | (val.IsStatic ? 16 : 0)), module.ImportReference(((MethodReference)val).ReturnType)); for (int i = 0; i < ((MethodReference)val).Parameters.Count; i++) { ParameterDefinition val3 = ((MethodReference)val).Parameters[i]; string text = ((keptArgumentNames != null && i < keptArgumentNames.Length) ? keptArgumentNames[i] : ((ParameterReference)val3).Name); ((MethodReference)val2).Parameters.Add(new ParameterDefinition(text, (ParameterAttributes)0, module.ImportReference(((ParameterReference)val3).ParameterType))); } ILProcessor iLProcessor = val2.Body.GetILProcessor(); if (!val.IsStatic) { iLProcessor.Emit(OpCodes.Ldarg_0); } Enumerator enumerator = ((MethodReference)val2).Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; iLProcessor.Emit(OpCodes.Ldarg, current); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static MethodDefinition EmitWithDefaults(ModuleDefinition module, TypeDefinition type, string name, string[] leading, object[] defaults) { //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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) int num = leading.Length; MethodDefinition val = null; Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name != name || ((MethodReference)current).Parameters.Count != num + defaults.Length) { continue; } bool flag = true; for (int i = 0; i < num; i++) { if (((MemberReference)((ParameterReference)((MethodReference)current).Parameters[i]).ParameterType).FullName != leading[i]) { flag = false; break; } } if (flag) { if (val != null) { return null; } val = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null || ((MethodReference)val).HasGenericParameters) { return null; } MethodDefinition val2 = new MethodDefinition(name, (MethodAttributes)(0x86 | (val.IsStatic ? 16 : 0)), module.ImportReference(((MethodReference)val).ReturnType)); for (int j = 0; j < num; j++) { ((MethodReference)val2).Parameters.Add(new ParameterDefinition(((ParameterReference)((MethodReference)val).Parameters[j]).Name, (ParameterAttributes)0, module.ImportReference(((ParameterReference)((MethodReference)val).Parameters[j]).ParameterType))); } ILProcessor iLProcessor = val2.Body.GetILProcessor(); if (!val.IsStatic) { iLProcessor.Emit(OpCodes.Ldarg_0); } Enumerator enumerator2 = ((MethodReference)val2).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current2 = enumerator2.Current; iLProcessor.Emit(OpCodes.Ldarg, current2); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } for (int k = 0; k < defaults.Length; k++) { TypeReference parameterType = ((ParameterReference)((MethodReference)val).Parameters[num + k]).ParameterType; if (!PushConstant(iLProcessor, defaults[k], parameterType)) { return null; } } iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static bool PushConstant(ILProcessor il, object value, TypeReference expected) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Invalid comparison between Unknown and I4 //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Invalid comparison between Unknown and I4 //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (value == null && !expected.IsValueType) { il.Emit(OpCodes.Ldnull); return true; } if (!(value is bool flag)) { if (!(value is int num)) { if (!(value is float num2)) { if (value is string text && (int)expected.MetadataType == 14) { il.Emit(OpCodes.Ldstr, text); return true; } } else if ((int)expected.MetadataType == 12) { il.Emit(OpCodes.Ldc_R4, num2); return true; } } else if ((int)expected.MetadataType == 8) { il.Emit(OpCodes.Ldc_I4, num); return true; } } else if ((int)expected.MetadataType == 2) { il.Emit(flag ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); return true; } return false; } private static MethodDefinition EmitClipboardClose(ModuleDefinition module, TypeDefinition clipboard) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown PropertyDefinition val = Property(clipboard, "_StatePreserved_k__BackingField") ?? Property(clipboard, "StatePreserved"); PropertyDefinition val2 = Property(clipboard, "State"); if (((val != null) ? val.SetMethod : null) == null || ((val2 != null) ? val2.GetMethod : null) == null) { return null; } MethodDefinition val3 = Method(((PropertyReference)val2).PropertyType.Resolve(), "PopFromDefaultParent", 0); if (val3 == null) { return null; } MethodDefinition val4 = new MethodDefinition("Close", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val4).Parameters.Add(new ParameterDefinition("preserveState", (ParameterAttributes)0, module.TypeSystem.Boolean)); ILProcessor iLProcessor = val4.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val.SetMethod)); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val2.GetMethod)); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Ret); return val4; } private static PropertyDefinition Property(TypeDefinition type, string name) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (type == null) { return null; } Enumerator enumerator = type.Properties.GetEnumerator(); try { while (enumerator.MoveNext()) { PropertyDefinition current = enumerator.Current; if (((MemberReference)current).Name == name) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static MethodDefinition EmitGetOrderDays(ModuleDefinition module, TypeDefinition customer) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown MethodDefinition val = Method(customer, "GetOrderDays", 3); if (val == null) { return null; } TypeReference val2 = module.ImportReference(((ParameterReference)((MethodReference)val).Parameters[2]).ParameterType); TypeDefinition val3 = val2.Resolve(); if (val3 == null) { return null; } MethodDefinition val4 = null; Enumerator enumerator = val3.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (current.IsConstructor && !current.IsStatic && ((MethodReference)current).Parameters.Count == 0) { val4 = current; break; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val4 == null) { return null; } MethodReference val5 = (MethodReference)((!(val2 is GenericInstanceType)) ? ((object)module.ImportReference((MethodReference)(object)val4)) : ((object)new MethodReference(((MemberReference)val4).Name, module.TypeSystem.Void, val2) { HasThis = true })); MethodDefinition val6 = new MethodDefinition("GetOrderDays", (MethodAttributes)134, val2); ((MethodReference)val6).Parameters.Add(new ParameterDefinition("dependence", (ParameterAttributes)0, module.ImportReference(((ParameterReference)((MethodReference)val).Parameters[0]).ParameterType))); ((MethodReference)val6).Parameters.Add(new ParameterDefinition("normalizedRelationship", (ParameterAttributes)0, module.ImportReference(((ParameterReference)((MethodReference)val).Parameters[1]).ParameterType))); VariableDefinition val7 = new VariableDefinition(val2); val6.Body.Variables.Add(val7); val6.Body.InitLocals = true; ILProcessor iLProcessor = val6.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Newobj, val5); iLProcessor.Emit(OpCodes.Stloc, val7); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Ldarg_2); iLProcessor.Emit(OpCodes.Ldloc, val7); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Ldloc, val7); iLProcessor.Emit(OpCodes.Ret); return val6; } private static MethodReference Itself(ModuleDefinition module, TypeDefinition owner, MethodDefinition target) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //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) if (!((TypeReference)owner).HasGenericParameters) { return module.ImportReference((MethodReference)(object)target); } GenericInstanceType val = new GenericInstanceType(module.ImportReference((TypeReference)(object)owner)); Enumerator enumerator = ((TypeReference)owner).GenericParameters.GetEnumerator(); try { while (enumerator.MoveNext()) { GenericParameter current = enumerator.Current; val.GenericArguments.Add((TypeReference)(object)current); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return module.ImportReference(ShadowTypes.On(val, target)); } private static MethodDefinition EmitAppExit(ModuleDefinition module, TypeDefinition app) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown TypeDefinition type = module.GetType("Il2CppScheduleOne.DevUtilities.ExitAction"); MethodDefinition val = Method(app, "Exit", 1); if (type == null || val == null) { return null; } string fullName = ((MemberReference)((ParameterReference)((MethodReference)val).Parameters[0]).ParameterType).FullName; TypeReference baseType = type.BaseType; if (fullName != ((baseType != null) ? ((MemberReference)baseType).FullName : null)) { return null; } MethodDefinition val2 = new MethodDefinition("Exit", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val2).Parameters.Add(new ParameterDefinition("action", (ParameterAttributes)0, module.ImportReference((TypeReference)(object)type))); ILProcessor iLProcessor = val2.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Call, Itself(module, app, val)); iLProcessor.Emit(OpCodes.Ret); return val2; } private static MethodDefinition EmitExitDelegateConversion(ModuleDefinition module, TypeDefinition exitDelegate) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Expected O, but got Unknown //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Expected O, but got Unknown TypeDefinition type = module.GetType("Il2CppScheduleOne.DevUtilities.ExitAction"); if (type == null) { return null; } MethodDefinition val = null; Enumerator enumerator = exitDelegate.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name == "op_Implicit" && ((MethodReference)current).Parameters.Count == 1 && ((ParameterReference)((MethodReference)current).Parameters[0]).ParameterType is GenericInstanceType) { val = current; break; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null) { return null; } GenericInstanceType val2 = (GenericInstanceType)((ParameterReference)((MethodReference)val).Parameters[0]).ParameterType; if (val2.GenericArguments.Count != 1) { return null; } string fullName = ((MemberReference)val2.GenericArguments[0]).FullName; TypeReference baseType = type.BaseType; if (fullName != ((baseType != null) ? ((MemberReference)baseType).FullName : null)) { return null; } TypeDefinition obj = ((TypeSpecification)val2).ElementType.Resolve(); MethodDefinition val3 = Method(obj, "Invoke", 1); MethodDefinition val4 = null; enumerator = (((obj != null) ? obj.Methods : null) ?? new Collection()).GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current2 = enumerator.Current; if (current2.IsConstructor && ((MethodReference)current2).Parameters.Count == 2) { val4 = current2; break; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val3 == null || val4 == null) { return null; } MethodDefinition val5 = ShadowTypes.PointerGetter(type.BaseType.Resolve()); MethodDefinition val6 = Method(type, ".ctor", 1); if (val5 == null || val6 == null) { return null; } GenericInstanceType val7 = new GenericInstanceType(((TypeSpecification)val2).ElementType); val7.GenericArguments.Add(module.ImportReference((TypeReference)(object)type)); TypeDefinition val8 = BuildExitShim(module, exitDelegate, type, val7, val3, val5, val6, val2); if (val8 == null) { return null; } MethodDefinition val9 = new MethodDefinition("op_Implicit", (MethodAttributes)2198, module.ImportReference((TypeReference)(object)exitDelegate)); ((MethodReference)val9).Parameters.Add(new ParameterDefinition("action", (ParameterAttributes)0, (TypeReference)(object)val7)); ILProcessor iLProcessor = val9.Body.GetILProcessor(); Instruction val10 = iLProcessor.Create(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Brtrue_S, val10); iLProcessor.Emit(OpCodes.Ldnull); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val10); iLProcessor.Emit(OpCodes.Newobj, (MethodReference)(object)MethodOf(val8, ".ctor")); iLProcessor.Emit(OpCodes.Ldftn, (MethodReference)(object)MethodOf(val8, "Invoke")); iLProcessor.Emit(OpCodes.Newobj, ShadowTypes.On(val2, val4)); iLProcessor.Emit(OpCodes.Call, (MethodReference)(object)val); iLProcessor.Emit(OpCodes.Ret); exitDelegate.NestedTypes.Add(val8); return val9; } private static TypeDefinition BuildExitShim(ModuleDefinition module, TypeDefinition owner, TypeDefinition shadow, GenericInstanceType actionOfShadow, MethodDefinition invokeDefinition, MethodDefinition pointer, MethodDefinition fromPointer, GenericInstanceType actionOfReal) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Expected O, but got Unknown TypeDefinition val = new TypeDefinition((string)null, "ExitActionShim", (TypeAttributes)1048834, module.TypeSystem.Object); FieldDefinition val2 = new FieldDefinition("action", (FieldAttributes)6, (TypeReference)(object)actionOfShadow); val.Fields.Add(val2); MethodReference val3 = new MethodReference(".ctor", module.TypeSystem.Void, module.TypeSystem.Object) { HasThis = true }; MethodDefinition val4 = new MethodDefinition(".ctor", (MethodAttributes)6278, module.TypeSystem.Void); ((MethodReference)val4).Parameters.Add(new ParameterDefinition("action", (ParameterAttributes)0, (TypeReference)(object)actionOfShadow)); ILProcessor iLProcessor = val4.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, val3); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Stfld, (FieldReference)(object)val2); iLProcessor.Emit(OpCodes.Ret); MethodDefinition val5 = new MethodDefinition("Invoke", (MethodAttributes)134, module.TypeSystem.Void); ((MethodReference)val5).Parameters.Add(new ParameterDefinition("exitAction", (ParameterAttributes)0, actionOfReal.GenericArguments[0])); ILProcessor iLProcessor2 = val5.Body.GetILProcessor(); Instruction val6 = iLProcessor2.Create(OpCodes.Callvirt, ShadowTypes.On(actionOfShadow, invokeDefinition)); Instruction val7 = iLProcessor2.Create(OpCodes.Call, module.ImportReference((MethodReference)(object)pointer)); iLProcessor2.Emit(OpCodes.Ldarg_0); iLProcessor2.Emit(OpCodes.Ldfld, (FieldReference)(object)val2); iLProcessor2.Emit(OpCodes.Ldarg_1); iLProcessor2.Emit(OpCodes.Dup); iLProcessor2.Emit(OpCodes.Brtrue_S, val7); iLProcessor2.Emit(OpCodes.Pop); iLProcessor2.Emit(OpCodes.Ldnull); iLProcessor2.Emit(OpCodes.Br_S, val6); iLProcessor2.Append(val7); iLProcessor2.Emit(OpCodes.Newobj, (MethodReference)(object)fromPointer); iLProcessor2.Append(val6); iLProcessor2.Emit(OpCodes.Ret); val.Methods.Add(val4); val.Methods.Add(val5); return val; } private static MethodDefinition MethodOf(TypeDefinition type, string name) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name == name) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static MethodDefinition EmitFromController(ModuleDefinition module, TypeDefinition owner, string accessor, string listProperty, string itemProperty, Action pushWanted) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = GetterUp(owner, "DialogueHandler"); object obj; if (val == null) { obj = null; } else { TypeReference returnType = ((MethodReference)val).ReturnType; obj = ((returnType != null) ? returnType.Resolve() : null); } TypeDefinition val2 = (TypeDefinition)obj; TypeDefinition type = module.GetType("Il2CppScheduleOne.Dialogue.DialogueController"); MethodDefinition val3 = Getter(type, listProperty); MethodReference val4 = GenericGetComponent(module, val2, type); if (val == null || val3 == null || val4 == null) { return null; } TypeReference returnType2 = ((MethodReference)val3).ReturnType; GenericInstanceType val5 = (GenericInstanceType)(object)((returnType2 is GenericInstanceType) ? returnType2 : null); if (val5 == null) { return null; } TypeDefinition type2 = ((TypeReference)val5).Resolve(); MethodDefinition val6 = Getter(type2, "Count"); MethodDefinition val7 = Method(type2, "get_Item", 1); TypeDefinition val8 = val5.GenericArguments[0].Resolve(); MethodDefinition val9 = Getter(val8, itemProperty); if (val6 == null || val7 == null || val9 == null) { return null; } MethodDefinition val10 = new MethodDefinition(accessor, (MethodAttributes)134, module.ImportReference((TypeReference)(object)val8)); VariableDefinition val11 = new VariableDefinition(module.TypeSystem.String); VariableDefinition val12 = new VariableDefinition(module.ImportReference((TypeReference)(object)val5)); VariableDefinition val13 = new VariableDefinition(module.TypeSystem.Int32); VariableDefinition val14 = new VariableDefinition(module.ImportReference((TypeReference)(object)val8)); val10.Body.Variables.Add(val11); val10.Body.Variables.Add(val12); val10.Body.Variables.Add(val13); val10.Body.Variables.Add(val14); val10.Body.InitLocals = true; ILProcessor iLProcessor = val10.Body.GetILProcessor(); Instruction val15 = iLProcessor.Create(OpCodes.Pop); Instruction val16 = iLProcessor.Create(OpCodes.Ldloc, val13); Instruction val17 = iLProcessor.Create(OpCodes.Ldloc, val13); Instruction val18 = iLProcessor.Create(OpCodes.Ldloc, val12); pushWanted(module, val10, iLProcessor, val15); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brfalse, val15); iLProcessor.Emit(OpCodes.Stloc, val11); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brfalse, val15); iLProcessor.Emit(OpCodes.Callvirt, val4); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brfalse, val15); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brfalse, val15); iLProcessor.Emit(OpCodes.Stloc, val12); iLProcessor.Emit(OpCodes.Ldc_I4_0); iLProcessor.Emit(OpCodes.Stloc, val13); iLProcessor.Emit(OpCodes.Br, val17); iLProcessor.Append(val18); iLProcessor.Emit(OpCodes.Ldloc, val13); iLProcessor.Emit(OpCodes.Callvirt, ShadowTypes.On(val5, val7)); iLProcessor.Emit(OpCodes.Stloc, val14); iLProcessor.Emit(OpCodes.Ldloc, val14); iLProcessor.Emit(OpCodes.Brfalse, val16); iLProcessor.Emit(OpCodes.Ldloc, val14); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val9)); iLProcessor.Emit(OpCodes.Ldloc, val11); iLProcessor.Emit(OpCodes.Call, StringEquality(module)); iLProcessor.Emit(OpCodes.Brfalse, val16); iLProcessor.Emit(OpCodes.Ldloc, val14); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val16); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Add); iLProcessor.Emit(OpCodes.Stloc, val13); iLProcessor.Append(val17); iLProcessor.Emit(OpCodes.Ldloc, val12); iLProcessor.Emit(OpCodes.Callvirt, ShadowTypes.On(val5, val6)); iLProcessor.Emit(OpCodes.Blt, val18); iLProcessor.Emit(OpCodes.Ldnull); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val15); iLProcessor.Emit(OpCodes.Ldnull); iLProcessor.Emit(OpCodes.Ret); return val10; } private static void MeetingGreetingLine(ModuleDefinition module, MethodDefinition method, ILProcessor il, Instruction giveUp) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = GetterUp(method.DeclaringType, "DialogueHandler"); object type; if (val == null) { type = null; } else { TypeReference returnType = ((MethodReference)val).ReturnType; type = ((returnType != null) ? returnType.Resolve() : null); } MethodDefinition val2 = Getter((TypeDefinition)type, "Database"); object type2; if (val2 == null) { type2 = null; } else { TypeReference returnType2 = ((MethodReference)val2).ReturnType; type2 = ((returnType2 != null) ? returnType2.Resolve() : null); } MethodDefinition val3 = Method((TypeDefinition)type2, "GetLine", 2); if (val == null || val2 == null || val3 == null) { il.Emit(OpCodes.Ldnull); return; } TypeDefinition obj = ((ParameterReference)((MethodReference)val3).Parameters[0]).ParameterType.Resolve(); int num = 0; bool flag = false; Enumerator enumerator = (((obj != null) ? obj.Fields : null) ?? new Collection()).GetEnumerator(); try { while (enumerator.MoveNext()) { FieldDefinition current = enumerator.Current; if (((MemberReference)current).Name == "Generic" && current.HasConstant) { num = Convert.ToInt32(current.Constant); flag = true; break; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (!flag) { il.Emit(OpCodes.Ldnull); return; } il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse, giveUp); il.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val2)); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse, giveUp); il.Emit(OpCodes.Ldc_I4, num); il.Emit(OpCodes.Ldstr, "supplier_meeting_greeting"); il.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); } private static MethodReference GenericGetComponent(ModuleDefinition module, TypeDefinition from, TypeDefinition wanted) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_0072: Expected O, but got Unknown if (from == null || wanted == null) { return null; } TypeDefinition val = from; while (val != null) { Enumerator enumerator = val.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (!(((MemberReference)current).Name != "GetComponent") && ((MethodReference)current).Parameters.Count == 0 && ((MethodReference)current).GenericParameters.Count == 1) { GenericInstanceMethod val2 = new GenericInstanceMethod(module.ImportReference((MethodReference)(object)current)); val2.GenericArguments.Add(module.ImportReference((TypeReference)(object)wanted)); return (MethodReference)val2; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } TypeDefinition val3 = null; try { TypeReference baseType = val.BaseType; val3 = ((baseType != null) ? baseType.Resolve() : null); } catch { } if (val3 == val) { return null; } val = val3; } return null; } private static MethodReference StringEquality(ModuleDefinition module) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = module.TypeSystem.String.Resolve().Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name == "op_Equality" && ((MethodReference)current).Parameters.Count == 2) { return module.ImportReference((MethodReference)(object)current); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static MethodDefinition EmitStorageClosedEvent(ModuleDefinition module, TypeDefinition menu) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown TypeDefinition val = Referenced(module, "UnityEngine.Events.UnityEvent"); if (val == null) { return null; } MethodDefinition val2 = null; Enumerator enumerator = val.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (current.IsConstructor && ((MethodReference)current).Parameters.Count == 0 && !current.IsStatic) { val2 = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val2 == null || Method(val, "Invoke", 0) == null) { return null; } TypeReference val3 = module.ImportReference((TypeReference)(object)val); FieldDefinition val4 = new FieldDefinition("onClosed", (FieldAttributes)22, val3); menu.Fields.Add(val4); MethodDefinition val5 = new MethodDefinition("get_onClosed", (MethodAttributes)134, val3); ILProcessor iLProcessor = val5.Body.GetILProcessor(); Instruction val6 = iLProcessor.Create(OpCodes.Ret); iLProcessor.Emit(OpCodes.Ldsfld, (FieldReference)(object)val4); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Brtrue, val6); iLProcessor.Emit(OpCodes.Pop); iLProcessor.Emit(OpCodes.Newobj, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Dup); iLProcessor.Emit(OpCodes.Stsfld, (FieldReference)(object)val4); iLProcessor.Append(val6); return val5; } private static TypeDefinition Referenced(ModuleDefinition module, string fullName) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) TypeDefinition type = module.GetType(fullName); if (type != null) { return type; } Enumerator enumerator = module.AssemblyReferences.GetEnumerator(); try { while (enumerator.MoveNext()) { AssemblyNameReference current = enumerator.Current; try { IAssemblyResolver assemblyResolver = module.AssemblyResolver; AssemblyDefinition obj = ((assemblyResolver != null) ? assemblyResolver.Resolve(current) : null); object obj2; if (obj == null) { obj2 = null; } else { ModuleDefinition mainModule = obj.MainModule; obj2 = ((mainModule != null) ? mainModule.GetType(fullName) : null); } TypeDefinition val = (TypeDefinition)obj2; if (val != null) { return val; } } catch { } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static MethodDefinition EmitNpcFullName(ModuleDefinition module, TypeDefinition npc) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown MethodDefinition val = Getter(npc, "NPCData"); MethodDefinition val2 = Getter(npc, "FullName"); object type; if (val == null) { type = null; } else { TypeReference returnType = ((MethodReference)val).ReturnType; type = ((returnType != null) ? returnType.Resolve() : null); } MethodDefinition val3 = Getter((TypeDefinition)type, "BasicInfo"); if (val == null || val2 == null || val3 == null) { return null; } if ((int)((MethodReference)val2).ReturnType.MetadataType != 14) { return null; } MethodDefinition val4 = new MethodDefinition("get_fullName", (MethodAttributes)2182, module.TypeSystem.String); ILProcessor iLProcessor = val4.Body.GetILProcessor(); Instruction val5 = iLProcessor.Create(OpCodes.Ldstr, ""); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Brfalse, val5); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Brfalse, val5); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val5); iLProcessor.Emit(OpCodes.Ret); return val4; } private static TypeDefinition Base(TypeDefinition type, string name) { TypeDefinition val = type; while (val != null) { if (((MemberReference)val).Name == name) { return val; } TypeReference baseType = val.BaseType; val = ((baseType != null) ? baseType.Resolve() : null); } return null; } private static MethodDefinition EmitLobbySteamId(ModuleDefinition module, TypeDefinition lobby) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Invalid comparison between Unknown and I4 //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Expected O, but got Unknown TypeDefinition val = SteamType(module, "CSteamID"); MethodDefinition val2 = Getter(lobby, "_lobbyService"); TypeDefinition type = module.GetType("Il2CppScheduleOne.Networking.SteamLobbyService"); if (val == null || val2 == null || type == null) { return null; } MethodDefinition val3 = Getter(type, "_lobbyID"); TypeReference returnType = ((MethodReference)val2).ReturnType; MethodDefinition obj = Getter((returnType != null) ? returnType.Resolve() : null, "Pointer"); if (obj == null) { TypeReference returnType2 = ((MethodReference)val2).ReturnType; obj = Getter(Base((returnType2 != null) ? returnType2.Resolve() : null, "Il2CppObjectBase"), "Pointer"); } MethodDefinition val4 = obj; MethodDefinition val5 = ShadowTypes.PointerConstructorOf(type); if (val3 == null) { throw new InvalidOperationException("SteamLobbyService._lobbyID is not here"); } if (val4 == null) { TypeReference returnType3 = ((MethodReference)val2).ReturnType; throw new InvalidOperationException("Il2CppObjectBase.Pointer is not reachable from " + ((returnType3 != null) ? ((MemberReference)returnType3).Name : null)); } if (val5 == null) { throw new InvalidOperationException("SteamLobbyService has no pointer constructor"); } MethodDefinition val6 = null; Enumerator enumerator = val.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (current.IsConstructor && ((MethodReference)current).Parameters.Count == 1 && (int)((ParameterReference)((MethodReference)current).Parameters[0]).ParameterType.MetadataType == 11) { val6 = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val6 == null) { return null; } MethodDefinition val7 = new MethodDefinition("get_LobbySteamID", (MethodAttributes)134, module.ImportReference((TypeReference)(object)val)); MethodBody body = val7.Body; VariableDefinition val8 = new VariableDefinition(module.ImportReference(((MethodReference)val2).ReturnType)); body.Variables.Add(val8); ILProcessor iLProcessor = body.GetILProcessor(); Instruction val9 = iLProcessor.Create(OpCodes.Ldc_I4_0); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Stloc, val8); iLProcessor.Emit(OpCodes.Ldloc, val8); iLProcessor.Emit(OpCodes.Brfalse, val9); iLProcessor.Emit(OpCodes.Ldloc, val8); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val4)); iLProcessor.Emit(OpCodes.Newobj, module.ImportReference((MethodReference)(object)val5)); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Newobj, module.ImportReference((MethodReference)(object)val6)); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val9); iLProcessor.Emit(OpCodes.Conv_U8); iLProcessor.Emit(OpCodes.Newobj, module.ImportReference((MethodReference)(object)val6)); iLProcessor.Emit(OpCodes.Ret); return val7; } private static MethodDefinition EmitNoPriceEvent(ModuleDefinition module, TypeDefinition owner) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown TypeDefinition val = module.GetType("UnityEngine.Events.UnityEvent") ?? ShadowTypes.Resolve(module, "UnityEngine.Events.UnityEvent", "UnityEngine.CoreModule"); if (val == null) { return null; } MethodDefinition val2 = new MethodDefinition("get_onPriceChanged", (MethodAttributes)134, module.ImportReference((TypeReference)(object)val)); ILProcessor iLProcessor = val2.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldnull); iLProcessor.Emit(OpCodes.Ret); return val2; } private static MethodDefinition EmitLocalPlayerId(ModuleDefinition module, TypeDefinition lobby) { //IL_0044: 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) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown TypeDefinition type = SteamType(module, "SteamUser"); TypeDefinition val = SteamType(module, "CSteamID"); MethodDefinition val2 = Method(type, "GetSteamID", 0); if (val == null || val2 == null || !val2.IsStatic) { return null; } MethodDefinition val3 = new MethodDefinition("get_LocalPlayerID", (MethodAttributes)134, module.ImportReference((TypeReference)(object)val)); ILProcessor iLProcessor = val3.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val2)); iLProcessor.Emit(OpCodes.Ret); return val3; } private static MethodDefinition EmitLobbyPlayers(ModuleDefinition module, TypeDefinition lobby) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Invalid comparison between Unknown and I4 //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Invalid comparison between Unknown and I4 //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = Method(lobby, "GetLobbyMemberIDs", 0); TypeDefinition val2 = SteamType(module, "CSteamID"); MethodDefinition val3 = Getter(lobby, "_lobbyService"); if (val == null || val2 == null || val3 == null) { return null; } TypeReference returnType = ((MethodReference)val).ReturnType; GenericInstanceType val4 = (GenericInstanceType)(object)((returnType is GenericInstanceType) ? returnType : null); TypeReference returnType2 = ((MethodReference)val).ReturnType; TypeDefinition type = ((returnType2 != null) ? returnType2.Resolve() : null); MethodDefinition val5 = Getter(type, "Count"); MethodDefinition val6 = Method(type, "get_Item", 1); if (val4 == null || val5 == null || val6 == null) { return null; } TypeReference obj = val4.GenericArguments[0]; MethodReference val7 = Against(module, val5, module.ImportReference((TypeReference)(object)val4)); MethodReference val8 = Against(module, val6, module.ImportReference((TypeReference)(object)val4)); if ((int)obj.MetadataType != 14) { return null; } MethodDefinition val9 = null; Enumerator enumerator = val2.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (current.IsConstructor && ((MethodReference)current).Parameters.Count == 1 && (int)((ParameterReference)((MethodReference)current).Parameters[0]).ParameterType.MetadataType == 11) { val9 = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val9 == null) { return null; } MethodReference val10 = TryParse(module); MethodReference size; MethodReference set; TypeReference val11 = StructArray(module, val2, out size, out set); if (val10 == null || val11 == null || size == null || set == null) { return null; } MethodDefinition val12 = new MethodDefinition("get_Players", (MethodAttributes)134, val11); VariableDefinition val13 = new VariableDefinition(module.ImportReference(((MethodReference)val).ReturnType)); VariableDefinition val14 = new VariableDefinition(val11); VariableDefinition val15 = new VariableDefinition(module.TypeSystem.Int32); VariableDefinition val16 = new VariableDefinition(module.TypeSystem.Int32); VariableDefinition val17 = new VariableDefinition(module.TypeSystem.UInt64); VariableDefinition[] array = (VariableDefinition[])(object)new VariableDefinition[5] { val13, val14, val15, val16, val17 }; foreach (VariableDefinition val18 in array) { val12.Body.Variables.Add(val18); } val12.Body.InitLocals = true; ILProcessor iLProcessor = val12.Body.GetILProcessor(); Instruction val19 = iLProcessor.Create(OpCodes.Ldc_I4_0); Instruction val20 = iLProcessor.Create(OpCodes.Ldloc, val15); Instruction val21 = iLProcessor.Create(OpCodes.Ldloc, val15); Instruction val22 = iLProcessor.Create(OpCodes.Nop); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Brfalse, val19); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Callvirt, module.ImportReference((MethodReference)(object)val)); iLProcessor.Emit(OpCodes.Stloc, val13); iLProcessor.Emit(OpCodes.Ldloc, val13); iLProcessor.Emit(OpCodes.Brfalse, val19); iLProcessor.Emit(OpCodes.Ldloc, val13); iLProcessor.Emit(OpCodes.Callvirt, val7); iLProcessor.Emit(OpCodes.Conv_I8); iLProcessor.Emit(OpCodes.Newobj, size); iLProcessor.Emit(OpCodes.Stloc, val14); iLProcessor.Emit(OpCodes.Br, val20); iLProcessor.Append(val22); iLProcessor.Emit(OpCodes.Ldloc, val13); iLProcessor.Emit(OpCodes.Ldloc, val15); iLProcessor.Emit(OpCodes.Callvirt, val8); iLProcessor.Emit(OpCodes.Ldloca, val17); iLProcessor.Emit(OpCodes.Call, val10); iLProcessor.Emit(OpCodes.Brfalse, val21); iLProcessor.Emit(OpCodes.Ldloc, val14); iLProcessor.Emit(OpCodes.Ldloc, val16); iLProcessor.Emit(OpCodes.Ldloc, val17); iLProcessor.Emit(OpCodes.Newobj, module.ImportReference((MethodReference)(object)val9)); iLProcessor.Emit(OpCodes.Callvirt, set); iLProcessor.Emit(OpCodes.Ldloc, val16); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Add); iLProcessor.Emit(OpCodes.Stloc, val16); iLProcessor.Append(val21); iLProcessor.Emit(OpCodes.Ldc_I4_1); iLProcessor.Emit(OpCodes.Add); iLProcessor.Emit(OpCodes.Stloc, val15); iLProcessor.Append(val20); iLProcessor.Emit(OpCodes.Ldloc, val13); iLProcessor.Emit(OpCodes.Callvirt, val7); iLProcessor.Emit(OpCodes.Blt, val22); iLProcessor.Emit(OpCodes.Ldloc, val14); iLProcessor.Emit(OpCodes.Ret); iLProcessor.Append(val19); iLProcessor.Emit(OpCodes.Conv_I8); iLProcessor.Emit(OpCodes.Newobj, size); iLProcessor.Emit(OpCodes.Ret); return val12; } private static TypeDefinition SteamType(ModuleDefinition module, string name) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = module.AssemblyReferences.GetEnumerator(); try { while (enumerator.MoveNext()) { AssemblyNameReference current = enumerator.Current; if (current.Name.IndexOf("steamworks", StringComparison.OrdinalIgnoreCase) < 0) { continue; } try { IAssemblyResolver assemblyResolver = module.AssemblyResolver; AssemblyDefinition obj = ((assemblyResolver != null) ? assemblyResolver.Resolve(current) : null); object obj2; if (obj == null) { obj2 = null; } else { ModuleDefinition mainModule = obj.MainModule; obj2 = ((mainModule != null) ? mainModule.GetType("Il2CppSteamworks." + name) : null); } TypeDefinition val = (TypeDefinition)obj2; if (val != null) { return val; } } catch { } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static MethodReference TryParse(ModuleDefinition module) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Invalid comparison between Unknown and I4 TypeDefinition val = module.TypeSystem.UInt64.Resolve(); if (val == null) { return null; } Enumerator enumerator = val.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name == "TryParse" && current.IsStatic && ((MethodReference)current).Parameters.Count == 2 && (int)((ParameterReference)((MethodReference)current).Parameters[0]).ParameterType.MetadataType == 14 && ((ParameterReference)((MethodReference)current).Parameters[1]).ParameterType.IsByReference) { return module.ImportReference((MethodReference)(object)current); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static TypeReference StructArray(ModuleDefinition module, TypeDefinition element, out MethodReference size, out MethodReference set) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Invalid comparison between Unknown and I4 size = null; set = null; TypeDefinition val = null; Enumerator enumerator = module.AssemblyReferences.GetEnumerator(); try { while (enumerator.MoveNext()) { AssemblyNameReference current = enumerator.Current; if (!current.Name.StartsWith("Il2CppInterop", StringComparison.OrdinalIgnoreCase)) { continue; } try { IAssemblyResolver assemblyResolver = module.AssemblyResolver; AssemblyDefinition obj = ((assemblyResolver != null) ? assemblyResolver.Resolve(current) : null); object obj2; if (obj == null) { obj2 = null; } else { ModuleDefinition mainModule = obj.MainModule; obj2 = ((mainModule != null) ? mainModule.Types : null); } IEnumerable enumerable = (IEnumerable)obj2; foreach (TypeDefinition item in enumerable ?? Array.Empty()) { if (((MemberReference)item).Name == "Il2CppStructArray`1") { val = item; break; } } } catch { } if (val != null) { break; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null || ((TypeReference)val).GenericParameters.Count != 1) { return null; } TypeReference val2 = module.ImportReference((TypeReference)(object)val); if (val2 == null) { return null; } GenericInstanceType val3 = new GenericInstanceType(val2); val3.GenericArguments.Add(module.ImportReference((TypeReference)(object)element)); MethodDefinition val4 = null; MethodDefinition val5 = null; Enumerator enumerator3 = val.Methods.GetEnumerator(); try { while (enumerator3.MoveNext()) { MethodDefinition current3 = enumerator3.Current; if (current3.IsConstructor && ((MethodReference)current3).Parameters.Count == 1 && (int)((ParameterReference)((MethodReference)current3).Parameters[0]).ParameterType.MetadataType == 10) { val4 = current3; } if (((MemberReference)current3).Name == "set_Item" && ((MethodReference)current3).Parameters.Count == 2) { val5 = current3; } } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } if (val4 == null) { return null; } if (val5 == null) { TypeDefinition val6 = null; try { TypeReference baseType = val.BaseType; val6 = ((baseType != null) ? baseType.Resolve() : null); } catch { } if (val6 == null || ((TypeReference)val6).GenericParameters.Count != 1) { return null; } enumerator3 = val6.Methods.GetEnumerator(); try { while (enumerator3.MoveNext()) { MethodDefinition current4 = enumerator3.Current; if (((MemberReference)current4).Name == "set_Item" && ((MethodReference)current4).Parameters.Count == 2) { val5 = current4; } } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } if (val5 == null) { return null; } GenericInstanceType val7 = new GenericInstanceType(module.ImportReference((TypeReference)(object)val6)); val7.GenericArguments.Add(module.ImportReference((TypeReference)(object)element)); set = Against(module, val5, (TypeReference)(object)val7); } else { set = Against(module, val5, (TypeReference)(object)val3); } size = Against(module, val4, (TypeReference)(object)val3); return (TypeReference)(object)val3; } private static MethodReference Against(ModuleDefinition module, MethodDefinition method, TypeReference owner) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0063: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown MethodReference val = new MethodReference(((MemberReference)method).Name, ((MethodReference)method).ReturnType, owner) { HasThis = ((MethodReference)method).HasThis, ExplicitThis = ((MethodReference)method).ExplicitThis, CallingConvention = ((MethodReference)method).CallingConvention }; Enumerator enumerator = ((MethodReference)method).Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; val.Parameters.Add(new ParameterDefinition(((ParameterReference)current).ParameterType)); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } Enumerator enumerator2 = ((MethodReference)method).GenericParameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { GenericParameter current2 = enumerator2.Current; val.GenericParameters.Add(new GenericParameter(((MemberReference)current2).Name, (IGenericParameterProvider)(object)val)); } return val; } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } private static Bridge FromBase(string declaringType, string oldName, string baseName, string because) { return new Bridge { Assembly = "Assembly-CSharp", DeclaringType = declaringType, OldName = "get_" + oldName, ParameterCount = 0, Because = because, Emit = (ModuleDefinition module, TypeDefinition type) => EmitFromBase(module, type, "get_" + oldName, "get_" + baseName) }; } private static MethodDefinition EmitFromBase(ModuleDefinition module, TypeDefinition type, string accessor, string target) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown TypeReference val = ((type != null) ? type.BaseType : null); if (val == null) { return null; } TypeDefinition type2 = null; try { type2 = val.Resolve(); } catch { } MethodDefinition val2 = Method(type2, target, 0); if (val2 == null || val2.IsStatic || ((MethodReference)val2).ReturnType == null) { return null; } if (((MemberReference)((MethodReference)val2).ReturnType).ContainsGenericParameter) { return null; } TypeReference val3 = module.ImportReference(((MethodReference)val2).ReturnType); MethodReference val4 = new MethodReference(((MemberReference)val2).Name, val3, module.ImportReference(val)) { HasThis = true }; MethodDefinition val5 = new MethodDefinition(accessor, (MethodAttributes)134, val3); ILProcessor iLProcessor = val5.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Call, val4); iLProcessor.Emit(OpCodes.Ret); return val5; } private static MethodDefinition GetterUp(TypeDefinition type, string member) { TypeDefinition val = type; while (val != null) { MethodDefinition val2 = Getter(val, member); if (val2 != null) { return val2; } TypeDefinition val3 = null; try { TypeReference baseType = val.BaseType; val3 = ((baseType != null) ? baseType.Resolve() : null); } catch { } if (val3 == val) { return null; } val = val3; } return null; } private static void EmitDefault(MethodDefinition method, ILProcessor il, TypeReference type) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) if (!type.IsValueType) { il.Emit(OpCodes.Ldnull); return; } VariableDefinition val = new VariableDefinition(type); method.Body.Variables.Add(val); il.Emit(OpCodes.Ldloca_S, val); il.Emit(OpCodes.Initobj, type); il.Emit(OpCodes.Ldloc_S, val); } private static MethodDefinition Getter(TypeDefinition type, string member) { return Method(type, "get_" + member, 0); } private static MethodDefinition MethodUp(TypeDefinition type, string name, int parameters) { TypeDefinition val = type; while (val != null) { MethodDefinition val2 = Method(val, name, parameters); if (val2 != null) { return val2; } TypeDefinition val3 = null; try { TypeReference baseType = val.BaseType; val3 = ((baseType != null) ? baseType.Resolve() : null); } catch { } if (val3 == val) { return null; } val = val3; } return null; } private static MethodDefinition Method(TypeDefinition type, string name, int parameters) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (type == null) { return null; } Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name == name && ((MethodReference)current).Parameters.Count == parameters) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static TypeDefinition Nested(TypeDefinition type, string name) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (type == null) { return null; } Enumerator enumerator = type.NestedTypes.GetEnumerator(); try { while (enumerator.MoveNext()) { TypeDefinition current = enumerator.Current; if (((MemberReference)current).Name == name) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } } internal static class Removed { internal const string NpcSelector = "Il2CppScheduleOne.UI.Management.NPCSelector"; internal static MethodDefinition EmitNpcSelectorGetter(ModuleDefinition module, TypeDefinition type) { //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_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) //IL_003d: Expected O, but got Unknown TypeDefinition val = Stub(module); if (val == null) { return null; } MethodDefinition val2 = new MethodDefinition("get_NPCSelector", (MethodAttributes)134, (TypeReference)(object)val); ILProcessor iLProcessor = val2.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldnull); iLProcessor.Emit(OpCodes.Ret); return val2; } private static TypeDefinition Stub(ModuleDefinition module) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown TypeDefinition type = module.GetType("Il2CppScheduleOne.UI.Management.NPCSelector"); if (type != null) { return type; } int num = "Il2CppScheduleOne.UI.Management.NPCSelector".LastIndexOf('.'); TypeDefinition val = new TypeDefinition("Il2CppScheduleOne.UI.Management.NPCSelector".Substring(0, num), "Il2CppScheduleOne.UI.Management.NPCSelector".Substring(num + 1), (TypeAttributes)1048577, module.ImportReference(module.TypeSystem.Object)); MethodDefinition val2 = new MethodDefinition("get_IsOpen", (MethodAttributes)2182, module.TypeSystem.Boolean); ILProcessor iLProcessor = val2.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldc_I4_0); iLProcessor.Emit(OpCodes.Ret); val.Methods.Add(val2); PropertyDefinition val3 = new PropertyDefinition("IsOpen", (PropertyAttributes)0, module.TypeSystem.Boolean) { GetMethod = val2 }; val.Properties.Add(val3); module.Types.Add(val); return val; } } } namespace Polyfill.Contract { internal static class CommandTable { internal sealed class Command { internal string Name; internal string Help; internal string Example; } internal static readonly Command[] All = new Command[12] { C("polyfill", "what Polyfill found in your mods at startup", "polyfill"), C("polyfilllist", "every mod, with its verdict", "polyfilllist"), C("polyfillshow", "everything one mod asks for that is missing", "polyfillshow hitman"), C("polyfillunfixed", "only what cannot be pointed at anything", "polyfillunfixed hitman"), C("polyfillexport", "write one file with everything, ready to send", "polyfillexport"), C("polyfillprobe", "can the runtime resolve this type, and does Type::Member really run?", "polyfillprobe Il2CppScheduleOne.UI.InputPromptsCanvas::LoadModule objectselector"), C("polyfillprefab", "does the game still have this prefab, and what is near it", "polyfillprefab Basic Metal Glass Door"), C("polyfillfixes", "the per-mod fixes, and switch one off", "polyfillfixes off s1mapi-prefabs"), C("polyfillrestore", "undo every repair, restart to take effect", "polyfillrestore"), C("polyfillregen", "have MelonLoader rebuild the game's generated assemblies", "polyfillregen"), C("polyfillshare", "share anonymous findings, or see what would be sent", "polyfillshare show"), C("polyfillhelp", "list the polyfill commands", "polyfillhelp") }; internal static bool Owns(string command) { if (string.IsNullOrEmpty(command)) { return false; } Command[] all = All; for (int i = 0; i < all.Length; i++) { if (string.Equals(all[i].Name, command, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static Command C(string name, string help, string example) { return new Command { Name = name, Help = help, Example = example }; } } internal interface IConsentStore { bool TryReadBool(string key, out bool value); bool TryReadInt(string key, out int value); void Write(string key, T value, string description); void Flush(); } internal static class Consent { internal sealed class State { internal bool Sharing; internal bool Answered; internal int Asked; } internal const string SharingKey = "ShareFindings"; internal const string AnsweredKey = "ShareFindingsAnswered"; internal const string AskedKey = "ShareFindingsAsked"; private static IConsentStore _store; internal static bool Sharing => Read().Sharing; internal static void Use(IConsentStore store) { _store = store; } internal static State Read() { State state = new State(); IConsentStore store = _store; if (store == null) { return state; } try { if (store.TryReadBool("ShareFindings", out var value)) { state.Sharing = value; } if (store.TryReadBool("ShareFindingsAnswered", out var value2)) { state.Answered = value2; } if (store.TryReadInt("ShareFindingsAsked", out var value3)) { state.Asked = value3; } } catch { } return state; } internal static void Write(bool sharing, bool answered) { IConsentStore store = _store; if (store == null) { return; } try { store.Write("ShareFindings", sharing, "Send anonymous findings - which mod, which symbol, repaired or not. Never your name, your paths or your save."); store.Write("ShareFindingsAnswered", answered, "Whether the question has been answered. Clear this to be asked again."); store.Flush(); } catch { } } internal static void CountOneAsk(State state) { IConsentStore store = _store; if (store == null) { return; } try { store.Write("ShareFindingsAsked", state.Asked + 1, "How many launches have asked. After three, the question stops."); store.Flush(); } catch { } } } internal static class CoveredElsewhere { internal sealed class Entry { internal string Type; internal string Member; internal string FixId; internal string Because; } internal static readonly Entry[] All = new Entry[3] { new Entry { Type = "Il2CppScheduleOne.UI.AmountSelector", Member = "get_onPriceChanged", FixId = "amount-changed-after-override", Because = "the UnityEvent this returned cannot be handed back - interop wrappers are pooled by weak reference, so it could not be the same object twice - but the change it announced is raised again when a mod replaces the setter that used to raise it" }, new Entry { Type = "Il2CppScheduleOne.UI.Handover.HandoverScreen", Member = "get_OriginalItemLocations", FixId = "otc-smart-fill-tracking", Because = "the dictionary and the nested enum it was keyed by are both gone, and nothing of that shape can be handed back - but it was write-only bookkeeping even in 0.4.5f2, so the fix drops the call instead of answering it" }, new Entry { Type = "Il2CppScheduleOne.UI.Handover.HandoverScreen/EItemSource", Member = null, FixId = "otc-smart-fill-tracking", Because = "the enum only ever typed HandoverScreen.OriginalItemLocations, and 0.4.6 deleted both - a copy would have its own identity and could not satisfy the signature. The one method that names it is OverTheCounter's TrackItemAsPlayer, and the fix takes the call to it out, so nothing reaches the name" } }; internal static Entry For(string type, string member) { if (type == null || member == null) { return null; } Entry[] all = All; foreach (Entry entry in all) { if (string.Equals(entry.Type, type, StringComparison.Ordinal) && string.Equals(entry.Member, member, StringComparison.Ordinal)) { return entry; } } return null; } internal static Entry ForType(string type) { if (type == null) { return null; } Entry[] all = All; foreach (Entry entry in all) { if (entry.Member == null && string.Equals(entry.Type, type, StringComparison.Ordinal)) { return entry; } } return null; } } internal readonly struct GameVersion : IComparable, IEquatable { internal readonly int[] Parts; internal readonly string Raw; internal static readonly GameVersion Unknown = new GameVersion(null, ""); internal bool IsKnown { get { if (Parts != null) { return Parts.Length != 0; } return false; } } private GameVersion(int[] parts, string raw) { Parts = parts; Raw = raw; } internal static bool TryParse(string text, out GameVersion version) { version = Unknown; if (string.IsNullOrEmpty(text)) { return false; } List list = new List(4); long num = 0L; bool flag = false; foreach (char c in text) { if (c >= '0' && c <= '9') { if (num < 214748364) { num = num * 10 + (c - 48); } flag = true; } else if (flag) { list.Add((int)num); num = 0L; flag = false; } } if (flag) { list.Add((int)num); } if (list.Count == 0) { return false; } version = new GameVersion(list.ToArray(), text); return true; } internal static GameVersion Parse(string text) { if (!TryParse(text, out var version)) { return Unknown; } return version; } public int CompareTo(GameVersion other) { int[] array = Parts ?? Array.Empty(); int[] array2 = other.Parts ?? Array.Empty(); int num = Math.Min(array.Length, array2.Length); for (int i = 0; i < num; i++) { if (array[i] != array2[i]) { if (array[i] >= array2[i]) { return 1; } return -1; } } return array.Length.CompareTo(array2.Length); } internal bool StartsWith(GameVersion prefix, int count) { if (Parts == null || prefix.Parts == null) { return false; } if (count > prefix.Parts.Length || count > Parts.Length) { return false; } for (int i = 0; i < count; i++) { if (Parts[i] != prefix.Parts[i]) { return false; } } return true; } public bool Equals(GameVersion other) { if (CompareTo(other) == 0) { return IsKnown == other.IsKnown; } return false; } public override bool Equals(object obj) { if (obj is GameVersion other) { return Equals(other); } return false; } public override int GetHashCode() { int num = 17; if (Parts != null) { int[] parts = Parts; foreach (int num2 in parts) { num = num * 31 + num2; } } return num; } public override string ToString() { if (!IsKnown) { return "unknown"; } return Raw; } public static bool operator <(GameVersion a, GameVersion b) { return a.CompareTo(b) < 0; } public static bool operator >(GameVersion a, GameVersion b) { return a.CompareTo(b) > 0; } public static bool operator <=(GameVersion a, GameVersion b) { return a.CompareTo(b) <= 0; } public static bool operator >=(GameVersion a, GameVersion b) { return a.CompareTo(b) >= 0; } public static bool operator ==(GameVersion a, GameVersion b) { return a.Equals(b); } public static bool operator !=(GameVersion a, GameVersion b) { return !a.Equals(b); } } internal static class GameVersionSource { private static string _raw; internal static string Raw => _raw ?? (_raw = Read()); internal static GameVersion Current => GameVersion.Parse(Raw); private static string Read() { string[] array = new string[2] { "MelonLoader.InternalUtils.UnityInformationHandler, MelonLoader", "MelonLoader.MelonUtils, MelonLoader" }; foreach (string typeName in array) { try { if ((Type.GetType(typeName, throwOnError: false)?.GetProperty("GameVersion", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null) is string { Length: >0 } text) { return text; } } catch { } } return "unknown"; } internal static string Disagreement(string other) { if (string.IsNullOrEmpty(other)) { return null; } if (GameVersion.Parse(other) == Current) { return null; } return $"MelonLoader says the game is '{Raw}' and Unity says '{other}'. Polyfill went with " + "MelonLoader's, which is the one every version decision was made against."; } } internal static class SplitScreens { internal sealed class Entry { internal string Type; internal string Station; internal string StationName; internal bool HasRemoveUi; } private const string Stations = "Il2CppScheduleOne.UI.Stations."; private const string Objects = "Il2CppScheduleOne.ObjectScripts."; internal static readonly Entry[] All = new Entry[5] { new Entry { Type = "Il2CppScheduleOne.UI.Stations.PackagingStationCanvas", Station = "Il2CppScheduleOne.ObjectScripts.PackagingStation", StationName = "station", HasRemoveUi = true }, new Entry { Type = "Il2CppScheduleOne.UI.Stations.BrickPressCanvas", Station = "Il2CppScheduleOne.ObjectScripts.BrickPress", StationName = "press", HasRemoveUi = true }, new Entry { Type = "Il2CppScheduleOne.UI.Stations.LabOvenCanvas", Station = "Il2CppScheduleOne.ObjectScripts.LabOven", StationName = "oven", HasRemoveUi = true }, new Entry { Type = "Il2CppScheduleOne.UI.Stations.CauldronCanvas", Station = "Il2CppScheduleOne.ObjectScripts.Cauldron", StationName = "cauldron", HasRemoveUi = true }, new Entry { Type = "Il2CppScheduleOne.UI.Stations.DryingRackCanvas", Station = "Il2CppScheduleOne.ObjectScripts.DryingRack", StationName = "rack", HasRemoveUi = false } }; } internal static class GrownOverloads { internal sealed class Entry { internal string Type; internal string Name; internal string[] OldParameters; internal string Because; } internal static readonly Entry[] All = new Entry[4] { new Entry { Type = "Il2CppScheduleOne.UI.StorageMenu", Name = "Open", OldParameters = new string[3] { "System.String", "System.String", "Il2CppScheduleOne.ItemFramework.IItemSlotOwner" }, Because = "0.4.6 gave every StorageMenu.Open a closing callback" }, new Entry { Type = "Il2CppScheduleOne.UI.StorageMenu", Name = "Open", OldParameters = new string[3] { "Il2CppScheduleOne.ItemFramework.IItemSlotOwner", "System.String", "System.String" }, Because = "0.4.6 gave every StorageMenu.Open a closing callback" }, new Entry { Type = "Il2CppScheduleOne.UI.StorageMenu", Name = "Open", OldParameters = new string[1] { "Il2CppScheduleOne.Storage.StorageEntity" }, Because = "the third Open took the same trailing callback as its two siblings and was missed when they were listed (0.4.5f2 Open_Public_Virtual_New_Void_StorageEntity_0 against 0.4.6f13 ..._StorageEntity_Action_0)" }, new Entry { Type = "Il2CppScheduleOne.Economy.CustomerData", Name = "GetOrderDays", OldParameters = new string[2] { "System.Single", "System.Single" }, Because = "GetOrderDays stopped returning the list and started filling one it is handed" } }; internal static bool Doubled(string type, string name) { Entry[] all = All; foreach (Entry entry in all) { if (entry.Name == name && string.Equals(entry.Type, type, StringComparison.Ordinal)) { return true; } } return false; } internal static bool IsStandIn(string type, string name, int parameterCount) { Entry[] all = All; foreach (Entry entry in all) { if (entry.Name == name && entry.OldParameters.Length == parameterCount && string.Equals(entry.Type, type, StringComparison.Ordinal)) { return true; } } return false; } } internal static class Headless { private static bool _asked; private static bool _answer; private static string _why; internal static bool Yes(out string why) { if (!_asked) { _asked = true; _answer = Look(out _why); } why = _why; return _answer; } internal static bool Yes() { string why; return Yes(out why); } private static bool Look(out string why) { why = null; try { string[] commandLineArgs = Environment.GetCommandLineArgs(); for (int i = 0; i < commandLineArgs.Length; i++) { switch (commandLineArgs[i].TrimStart('-').ToLowerInvariant()) { case "batchmode": why = "the game is running in batch mode"; return true; case "nographics": why = "the game is running without graphics"; return true; case "dedicated-server": case "dedicatedserver": why = "this is a dedicated server"; return true; } } } catch (Exception) { } return false; } } internal interface ILog { void Msg(string message); void Warning(string message); void Error(string message); } internal static class NarrowedOverloads { internal sealed class Entry { internal string Type; internal string Name; internal string[] RealParameters; internal string ParameterName; internal string Because; } internal static readonly Entry[] All = new Entry[1] { new Entry { Type = "Il2CppScheduleOne.UI.Phone.CounterofferInterface", Name = "ChangeQuantity", RealParameters = new string[1] { "System.Single" }, ParameterName = "change", Because = "the quantity step took an int until 0.4.5f2 and takes a float now, and a second ChangeQuantity(string) arrived beside it for the text box (CounterofferInterface.cs:191-207)" } }; } internal static class PolyfillPaths { internal const string BackupSuffix = ".polyfill-orig"; internal const string TempSuffix = ".polyfill-tmp"; internal const string FolderName = "Polyfill"; internal const string LastRunFile = "last-run.txt"; internal const string ReportFile = "polyfill-report.txt"; internal const string StampFileName = "interop.stamp"; internal const string RestorePendingFile = "restore-pending"; internal static string Folder(string userDataDirectory) { return Path.Combine(userDataDirectory ?? ".", "Polyfill"); } internal static string LastRun(string userDataDirectory) { return Path.Combine(Folder(userDataDirectory), "last-run.txt"); } internal static string Report(string userDataDirectory) { return Path.Combine(Folder(userDataDirectory), "polyfill-report.txt"); } internal static string Stamp(string userDataDirectory) { return Path.Combine(Folder(userDataDirectory), "interop.stamp"); } internal static string RestorePending(string userDataDirectory) { return Path.Combine(Folder(userDataDirectory), "restore-pending"); } internal static string Backup(string assemblyPath) { return assemblyPath + ".polyfill-orig"; } } internal static class RenamedMethods { internal sealed class Entry { internal string Type; internal string OldName; internal string NewName; internal string Because; } internal static readonly Entry[] All = new Entry[2] { new Entry { Type = "Il2CppScheduleOne.ObjectScripts.PackagingStation", OldName = "Open", NewName = "Use", Because = "0.4.5f2 PackagingStation.Open() set the camera up and opened the canvas; 0.4.6f13 Use() pushes a state and opens the canvas, on the same type (PackagingStation.cs:405)" }, new Entry { Type = "Il2CppScheduleOne.UI.Handover.HandoverScreenPriceSelector", OldName = "SetPrice", NewName = "SetAmount", Because = "the price control became the game's general amount box in 0.4.6, and SetPrice(float) became SetAmount(float) on it (AmountSelector.cs:61)" } }; internal static string Successor(string type, string oldName) { if (type == null || oldName == null) { return null; } Entry[] all = All; foreach (Entry entry in all) { if (string.Equals(entry.Type, type, StringComparison.Ordinal) && string.Equals(entry.OldName, oldName, StringComparison.Ordinal)) { return entry.NewName; } } return null; } internal static string Because(string type, string oldName) { if (type == null || oldName == null) { return null; } Entry[] all = All; foreach (Entry entry in all) { if (string.Equals(entry.Type, type, StringComparison.Ordinal) && string.Equals(entry.OldName, oldName, StringComparison.Ordinal)) { return entry.Because; } } return null; } } internal static class RenamedParameters { internal sealed class Entry { internal string Type; internal string Method; internal int ParameterCount; internal int Index; internal string OldName; internal string NewName; internal string Because; } internal static readonly Entry[] All = new Entry[2] { new Entry { Type = "Il2CppScheduleOne.UI.Shop.ShopInterface", Method = "SetIsOpen", ParameterCount = 1, Index = 0, OldName = "isOpen", NewName = "open", Because = "the flag kept its type and its meaning and lost its name in 0.4.6" }, new Entry { Type = "Il2CppScheduleOne.UI.AmountSelector", Method = "SetAmount", ParameterCount = 1, Index = 0, OldName = "price", NewName = "amount", Because = "SetPrice(float price) became SetAmount(float amount) when the handover price control turned into the game's general amount box (AmountSelector.cs:61)" } }; internal static IEnumerable For(string type, string method, int parameterCount) { Entry[] all = All; foreach (Entry entry in all) { if (entry.Method == method && entry.ParameterCount == parameterCount && string.Equals(entry.Type, type, StringComparison.Ordinal)) { yield return entry; } } } } internal static class RenamedTypes { internal static readonly string[] StandIns = new string[10] { "Il2CppScheduleOne.UI.Stations.MixingStationCanvas", "Il2CppScheduleOne.UI.Stations.ChemistryStationCanvas", "Il2CppScheduleOne.UI.Stations.CauldronCanvas", "Il2CppScheduleOne.UI.Stations.DryingRackCanvas", "Il2CppScheduleOne.UI.Handover.HandoverScreenPriceSelector", "Il2CppScheduleOne.Weather.WeatherConditions", "Il2CppScheduleOne.DevUtilities.ExitAction", "Il2CppScheduleOne.UI.ATM.ATMInterface", "Il2CppScheduleOne.UI.Stations.Drying_rack.DryingOperationUI", "Il2CppScheduleOne.UI.MainMenu.MainMenuScreen" }; internal static bool IsStandIn(string fullName) { if (fullName == null) { return false; } string[] standIns = StandIns; for (int i = 0; i < standIns.Length; i++) { if (string.Equals(standIns[i], fullName, StringComparison.Ordinal)) { return true; } } return false; } } internal static class ReplacedMethods { internal sealed class Replacement { internal string Name; internal string[] Parameters = new string[0]; internal object[] Arguments = new object[0]; } internal sealed class Entry { internal string Type; internal string OldName; internal string[] Parameters; internal string[] ParameterNames; internal Replacement[] Replacements; internal string Because; } private const string Bool = "System.Boolean"; private const string Management = "Il2CppScheduleOne.UI.Management."; internal static readonly Entry[] All = new Entry[2] { Selector("ObjectSelector"), Selector("TransitEntitySelector") }; private static Entry Selector(string type) { Entry entry = new Entry(); entry.Type = "Il2CppScheduleOne.UI.Management." + type; entry.OldName = "Close"; entry.Parameters = new string[2] { "System.Boolean", "System.Boolean" }; entry.ParameterNames = new string[2] { "returnToClipboard", "pushChanges" }; entry.Replacements = new Replacement[2] { new Replacement { Name = "CloseAndSubmit", Arguments = new object[2] { true, true } }, new Replacement { Name = "CloseAndCancel", Arguments = new object[2] { true, false } } }; entry.Because = "0.4.5f2 " + type + ".Close(bool returnToClipboard, bool pushChanges); 0.4.6f13 has CloseAndSubmit and CloseAndCancel over a shared OnClose that always returns to the clipboard (ObjectSelector.cs:120-143)"; return entry; } } internal static class Outcome { internal const string Applied = "applied"; internal const string Refused = "refused"; internal const string StoodDown = "stood-down"; internal const string None = "none"; } internal sealed class Finding { internal string Kind; internal bool Note; internal string Scope; internal string Symbol; internal string Reason; internal string Hint; internal string Site; internal string Outcome = "none"; internal string OutcomeDetail; internal bool Covered; internal string RepairKey; internal bool Fixable => !string.IsNullOrEmpty(Hint); } internal sealed class ModReport { internal string Path; internal string AssemblyName; internal string Name; internal string Version; internal string Author; internal int TypeRefs; internal int MemberRefs; internal int HarmonyTargetsChecked; internal readonly List Findings = new List(); internal readonly List Namespaces = new List(); internal string Display { get { if (string.IsNullOrEmpty(Name)) { if (string.IsNullOrEmpty(AssemblyName)) { return System.IO.Path.GetFileName(Path ?? ""); } return AssemblyName; } return Name; } } internal string Verdict { get { bool flag = false; foreach (Finding finding in Findings) { if (!finding.Note) { flag = true; if (!(finding.Outcome == "applied") && !finding.Covered) { return "blocked"; } } } if (!flag) { return "clean"; } return "adaptable"; } } } internal sealed class RunReport { internal const int Format = 2; internal const string HeaderPrefix = "# polyfill-report "; private const char CarriageReturn = '\r'; internal string Generated = ""; internal string Game = "?"; internal string Interop = ""; internal int AssemblyCount; internal readonly List Mods = new List(); internal readonly List Dropped = new List(); internal string Problem; internal string Text() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# polyfill-report " + 2); stringBuilder.AppendLine("# generated=" + Escape(Generated)); stringBuilder.AppendLine("# game=" + Escape(Game)); stringBuilder.AppendLine("# interop=" + Escape(Interop)); stringBuilder.AppendLine("# assemblies=" + AssemblyCount); stringBuilder.AppendLine("# mods=" + Mods.Count); foreach (ModReport mod in Mods) { stringBuilder.AppendLine(string.Join("|", "M", Escape(mod.Path), Escape(mod.AssemblyName), Escape(mod.Name), Escape(mod.Version), Escape(mod.Author), mod.Verdict, mod.TypeRefs.ToString(), mod.MemberRefs.ToString(), mod.HarmonyTargetsChecked.ToString(), mod.Findings.Count.ToString())); foreach (Finding finding in mod.Findings) { stringBuilder.AppendLine(string.Join("|", "F", Escape(mod.Path), Escape(finding.Kind), Escape(finding.Scope), Escape(finding.Symbol), Escape(finding.Reason), Escape(finding.Hint), Escape(finding.Site), Escape(finding.Outcome), Escape(finding.OutcomeDetail))); } } foreach (ModReport mod2 in Mods) { if (mod2.Namespaces.Count > 0) { stringBuilder.AppendLine(string.Join("|", "N", Escape(mod2.Path), Escape(string.Join(",", mod2.Namespaces)))); } } foreach (string item in Dropped) { stringBuilder.AppendLine("D|" + Escape(item)); } return stringBuilder.ToString(); } internal static RunReport Read(IEnumerable lines) { RunReport runReport = new RunReport(); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); bool flag = false; foreach (string line in lines) { if (line == null) { continue; } string text = line.TrimEnd('\r'); if (!flag) { if (!text.StartsWith("# polyfill-report ", StringComparison.Ordinal)) { runReport.Problem = "this is not a Polyfill report"; return runReport; } string text2 = text.Substring("# polyfill-report ".Length).Trim(); if (!int.TryParse(text2, out var result)) { runReport.Problem = "the format is written as '" + text2 + "', which is not a number"; return runReport; } if (result > 2) { runReport.Problem = $"it is format {result} and this build reads {2}. " + "Polyfill.dll in Mods/ and Polyfill.Boot.dll in Plugins/ are from different releases - update both."; return runReport; } flag = true; } else if (text.StartsWith("# game=", StringComparison.Ordinal)) { runReport.Game = text.Substring(7); } else if (text.StartsWith("# interop=", StringComparison.Ordinal)) { runReport.Interop = text.Substring(10); } else if (text.StartsWith("# generated=", StringComparison.Ordinal)) { runReport.Generated = text.Substring(12); } else if (text.StartsWith("# assemblies=", StringComparison.Ordinal)) { runReport.AssemblyCount = Int(text.Substring(13)); } else { if (text.Length == 0 || text[0] == '#') { continue; } string[] array = text.Split('|'); switch (array[0]) { case "M": if (array.Length >= 10) { ModReport modReport = new ModReport { Path = array[1], AssemblyName = array[2], Name = array[3], Version = array[4], Author = array[5], TypeRefs = Int(array[7]), MemberRefs = Int(array[8]), HarmonyTargetsChecked = Int(array[9]) }; runReport.Mods.Add(modReport); dictionary[modReport.Path] = modReport; } break; case "F": { if (array.Length >= 8 && dictionary.TryGetValue(array[1], out var value)) { value.Findings.Add(new Finding { Kind = array[2], Scope = array[3], Symbol = array[4], Reason = array[5], Hint = array[6], Site = array[7], Outcome = ((array.Length > 8) ? array[8] : "none"), OutcomeDetail = ((array.Length > 9) ? array[9] : "") }); } break; } case "N": { if (array.Length < 3 || !dictionary.TryGetValue(array[1], out var value2)) { break; } string[] array2 = array[2].Split(','); foreach (string text3 in array2) { if (!string.IsNullOrEmpty(text3)) { value2.Namespaces.Add(text3); } } break; } case "D": if (array.Length >= 2) { runReport.Dropped.Add(array[1]); } break; } } } if (!flag) { runReport.Problem = "the file is empty"; } return runReport; } private static int Int(string s) { if (!int.TryParse(s, out var result)) { return 0; } return result; } internal static string Escape(string value) { if (!string.IsNullOrEmpty(value)) { return value.Replace('|', '/').Replace('\r', ' ').Replace('\n', ' '); } return ""; } } internal static class SplitMethods { internal sealed class Entry { internal string Type; internal string Name; internal string[] StandInParameters; internal string[] RealParameters; internal string Because; } internal static readonly Entry[] All = new Entry[1] { new Entry { Type = "Il2CppScheduleOne.Tools.ManagementClipboard", Name = "Close", StandInParameters = new string[1] { "System.Boolean" }, RealParameters = new string[0], Because = "the player's own exit calls Close() and never the flagged one, so a mod's postfix on the old signature stopped seeing ordinary closes" } }; } internal sealed class VersionDb { internal static class Op { internal const string Rename = "R"; internal const string Removed = "-"; internal const string Ambiguous = "?"; internal const string Merge = "M"; } internal static class Origin { internal const string Derived = "derived"; internal const string Curated = "curated"; internal const string Override = "override"; } internal sealed class Row { internal string Op; internal string Kind; internal string Type; internal string From; internal string To; internal string RuleName; internal string Confidence; internal string Note; internal string Origin; internal int Arity; internal string Key => Kind + "|" + Type + "|" + From + "|" + Arity; internal string NameKey => Kind + "|" + Type + "|" + From; } internal sealed class Step { internal GameVersion From; internal GameVersion To; internal string Source = ""; internal readonly Dictionary Renames = new Dictionary(StringComparer.Ordinal); internal readonly Dictionary Removed = new Dictionary(StringComparer.Ordinal); internal readonly HashSet Refused = new HashSet(StringComparer.Ordinal); } internal const string HeaderPrefix = "# polyfill-versiondb "; internal const int Format = 1; private readonly List _steps = new List(); private readonly Dictionary _overrides = new Dictionary(StringComparer.Ordinal); private readonly List _overrideRanges = new List(); internal readonly List Notes = new List(); internal int RenameCount { get; private set; } internal int StepCount => _steps.Count; internal GameVersion Newest { get { if (_steps.Count != 0) { List steps = _steps; return steps[steps.Count - 1].To; } return GameVersion.Unknown; } } internal static VersionDb Load(IEnumerable<(string Name, IEnumerable Lines)> files) { VersionDb versionDb = new VersionDb(); Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (var file in files) { try { versionDb.ReadOne(file.Name, file.Lines, dictionary); } catch (Exception ex) { versionDb.Notes.Add(file.Name + " could not be read (" + ex.Message + ")"); } } versionDb._steps.AddRange(dictionary.Values); versionDb._steps.Sort((Step a, Step b) => a.From.CompareTo(b.From)); foreach (Step step in versionDb._steps) { versionDb.RenameCount += step.Renames.Count; } return versionDb; } private void ReadOne(string name, IEnumerable lines, Dictionary steps) { Step step = null; VersionRange range = null; bool flag = false; List list = new List(); foreach (string line in lines) { if (line == null) { continue; } string text = line.TrimEnd('\r'); if (!flag) { if (!text.StartsWith("# polyfill-versiondb ", StringComparison.Ordinal)) { Notes.Add(name + " is not a version database"); return; } if (!int.TryParse(text.Substring("# polyfill-versiondb ".Length).Trim(), out var result) || result > 1) { Notes.Add(name + " is a newer format than this build reads; skipped"); return; } flag = true; } else if (text.StartsWith("# from=", StringComparison.Ordinal)) { (step ?? (step = new Step())).From = GameVersion.Parse(text.Substring(7)); } else if (text.StartsWith("# to=", StringComparison.Ordinal)) { (step ?? (step = new Step())).To = GameVersion.Parse(text.Substring(5)); } else if (text.StartsWith("# source=", StringComparison.Ordinal)) { (step ?? (step = new Step())).Source = text.Substring(9); } else if (text.StartsWith("# applies=", StringComparison.Ordinal)) { if (!VersionRange.TryParse(text.Substring(10), out range, out var problem)) { Notes.Add($"{name} applies to '{text.Substring(10)}', which is not a range ({problem})"); return; } } else { if (text.Length == 0 || text[0] == '#') { continue; } Row row = Parse(text); if (row == null) { continue; } if (range != null) { TakeOverride(name, row, range); continue; } if (step == null) { Notes.Add(name + " has rows but no step"); return; } switch (row.Op) { case "R": list.Add(row); break; case "-": step.Removed[row.Key] = row; break; case "?": case "M": step.Refused.Add(row.NameKey); break; } } } if (range != null) { return; } if (step == null || !step.From.IsKnown || !step.To.IsKnown) { Notes.Add(name + " does not say which two builds it is between"); return; } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (Row item in list) { if (step.Renames.TryGetValue(item.Key, out var value)) { step.Refused.Add(item.NameKey); step.Renames.Remove(item.Key); Notes.Add($"{name}: {item.Type}.{item.From} is renamed twice in one step ({value.To} and {item.To}); neither is used"); continue; } string key = item.Kind + "|" + item.Type + "|" + item.To + "|" + item.Arity; if (dictionary.TryGetValue(key, out var value2)) { step.Refused.Add(item.NameKey); step.Refused.Add(value2.NameKey); step.Renames.Remove(value2.Key); Notes.Add($"{name}: {value2.From} and {item.From} both became {item.To} on {item.Type}; " + "neither is used"); } else { dictionary[key] = item; step.Renames[item.Key] = item; } } string text2 = step.From.ToString() + "->" + step.To; if (steps.ContainsKey(text2)) { Notes.Add(name + " replaces the step " + text2 + " that was loaded before it"); } steps[text2] = step; } private void TakeOverride(string name, Row row, VersionRange applies) { if (row.Origin == "override" && string.IsNullOrEmpty(row.Note)) { Notes.Add($"{name}: {row.Type}.{row.From} overrides the history with no reason given; skipped"); } else if (_overrides.ContainsKey(row.Key)) { Notes.Add($"{name}: {row.Type}.{row.From} is decided twice by hand; neither is used"); _overrides.Remove(row.Key); } else { _overrides[row.Key] = row; _overrideRanges.Add(applies); } } private static Row Parse(string line) { string[] array = line.Split('|'); if (array.Length < 10) { return null; } int result; return new Row { Op = array[0], Kind = array[1], Type = array[2], From = array[3], To = array[4], Arity = (int.TryParse(array[5], out result) ? result : 0), Origin = array[6], RuleName = array[7], Confidence = array[8], Note = array[9] }; } internal string Successor(string kind, string type, string name, int arity, GameVersion game) { string key = kind + "|" + type + "|" + name + "|" + arity; if (_overrides.TryGetValue(key, out var value)) { return value.To; } string text = name; foreach (Step step in _steps) { if (game.IsKnown && step.To > game) { break; } string text2 = kind + "|" + type + "|" + text; if (step.Refused.Contains(text2)) { return null; } if (step.Renames.TryGetValue(text2 + "|" + arity, out var value2)) { text = value2.To; } } if (!(text == name)) { return text; } return null; } internal string RemovedIn(string kind, string type, string name, int arity) { string key = kind + "|" + type + "|" + name + "|" + arity; foreach (Step step in _steps) { if (step.Removed.ContainsKey(key)) { return step.To.ToString(); } } return null; } internal bool WasRefused(string kind, string type, string name) { string item = kind + "|" + type + "|" + name; foreach (Step step in _steps) { if (step.Refused.Contains(item)) { return true; } } return false; } internal IEnumerable Versions() { foreach (Step step in _steps) { yield return step.From.ToString(); } if (_steps.Count > 0) { List steps = _steps; yield return steps[steps.Count - 1].To.ToString(); } } internal string Gap() { for (int i = 1; i < _steps.Count; i++) { if (_steps[i - 1].To != _steps[i].From) { return $"{_steps[i - 1].To} is followed by a step that starts at {_steps[i].From}"; } } return null; } } internal sealed class VersionRange { private enum Kind { Any, Prefix, AtLeast, Above, AtMost, Below, Between, Exact } private readonly struct Term { internal readonly Kind Kind; internal readonly GameVersion Low; internal readonly GameVersion High; internal readonly int PrefixParts; internal Term(Kind kind, GameVersion low, GameVersion high = default(GameVersion), int prefixParts = 0) { Kind = kind; Low = low; High = high; PrefixParts = prefixParts; } } private readonly Term[] _terms; internal static readonly VersionRange Any = new VersionRange(new Term[1] { new Term(Kind.Any, GameVersion.Unknown) }, "*"); internal static readonly VersionRange None = new VersionRange(Array.Empty(), "nothing"); internal string Text { get; } private VersionRange(Term[] terms, string text) { _terms = terms; Text = text; } internal static VersionRange Parse(string text) { if (!TryParse(text, out var range, out var problem)) { throw new FormatException("'" + text + "' is not a version range: " + problem); } return range; } internal static bool TryParse(string text, out VersionRange range, out string problem) { range = null; problem = null; if (string.IsNullOrWhiteSpace(text)) { range = Any; return true; } List list = new List(); string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0) { continue; } if (text2 == "*") { list.Add(new Term(Kind.Any, GameVersion.Unknown)); continue; } if (text2.EndsWith("*", StringComparison.Ordinal)) { if (!GameVersion.TryParse(text2.Substring(0, text2.Length - 1).TrimEnd('.', 'f', ' '), out var version)) { problem = "'" + text2 + "' has no version in front of the star"; return false; } list.Add(new Term(Kind.Prefix, version, default(GameVersion), version.Parts.Length)); continue; } int num = text2.IndexOf("..", StringComparison.Ordinal); if (num > 0) { if (!GameVersion.TryParse(text2.Substring(0, num), out var version2) || !GameVersion.TryParse(text2.Substring(num + 2), out var version3)) { problem = "'" + text2 + "' is not two versions with .. between them"; return false; } if (version2 > version3) { problem = "'" + text2 + "' starts after it ends"; return false; } list.Add(new Term(Kind.Between, version2, version3)); continue; } Kind kind = Kind.Exact; string text3 = text2; if (text3.StartsWith(">=", StringComparison.Ordinal)) { kind = Kind.AtLeast; text3 = text3.Substring(2); } else if (text3.StartsWith("<=", StringComparison.Ordinal)) { kind = Kind.AtMost; text3 = text3.Substring(2); } else if (text3.StartsWith(">", StringComparison.Ordinal)) { kind = Kind.Above; text3 = text3.Substring(1); } else if (text3.StartsWith("<", StringComparison.Ordinal)) { kind = Kind.Below; text3 = text3.Substring(1); } if (!GameVersion.TryParse(text3.Trim(), out var version4)) { problem = "'" + text2 + "' has no version in it"; return false; } list.Add(new Term(kind, version4)); } if (list.Count == 0) { problem = "it is empty"; return false; } range = new VersionRange(list.ToArray(), text); return true; } internal bool Allows(GameVersion version) { return Matches(version, unknownAnswer: false); } internal bool AllowsOrUnknown(GameVersion version) { return Matches(version, unknownAnswer: true); } internal bool Allows(string version) { return Allows(GameVersion.Parse(version)); } internal bool AllowsOrUnknown(string version) { return AllowsOrUnknown(GameVersion.Parse(version)); } private bool Matches(GameVersion version, bool unknownAnswer) { Term[] terms = _terms; for (int i = 0; i < terms.Length; i++) { Term term = terms[i]; if (term.Kind == Kind.Any) { return true; } if (!version.IsKnown) { return unknownAnswer; } if (term.Kind switch { Kind.Prefix => version.StartsWith(term.Low, term.PrefixParts), Kind.AtLeast => version >= term.Low, Kind.Above => version > term.Low, Kind.AtMost => version <= term.Low, Kind.Below => version < term.Low, Kind.Between => version >= term.Low && version <= term.High, _ => version == term.Low, }) { return true; } } return false; } public override string ToString() { return Text; } internal IEnumerable Bounds() { Term[] terms = _terms; for (int i = 0; i < terms.Length; i++) { Term term = terms[i]; if (term.Kind != Kind.Any) { if (term.Low.IsKnown) { yield return term.Low; } if (term.Kind == Kind.Between && term.High.IsKnown) { yield return term.High; } } } } internal string Describe() { StringBuilder stringBuilder = new StringBuilder(); Term[] terms = _terms; for (int i = 0; i < terms.Length; i++) { Term term = terms[i]; if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } StringBuilder stringBuilder2 = stringBuilder; stringBuilder2.Append(term.Kind switch { Kind.Any => "any build", Kind.Prefix => term.Low.ToString() + " and its builds", Kind.AtLeast => term.Low.ToString() + " and newer", Kind.Above => "newer than " + term.Low, Kind.AtMost => term.Low.ToString() + " and older", Kind.Below => "older than " + term.Low, Kind.Between => term.Low.ToString() + " to " + term.High, _ => term.Low.ToString(), }); } return stringBuilder.ToString(); } } } namespace Polyfill.Dynamic { internal static class ReflectionFallback { private static Instance _log; private static string _interop; private static readonly Dictionary _answers = new Dictionary(StringComparer.Ordinal); private static Dictionary> _gameBySimpleName; private static bool _gameIndexBuilt; internal static void Install(Instance log, string interopDirectory) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown _log = log; _interop = interopDirectory; try { MethodInfo methodInfo = AccessTools.Method(typeof(AccessTools), "TypeByName", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo == null) { log.Warning("[reflect] this Harmony has no AccessTools.TypeByName(string); left alone."); return; } new Harmony("doodesch.polyfill.reflection").Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ReflectionFallback), "TypeByNamePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.Msg("[reflect] type lookups answer from metadata; nothing enumerates interop types."); MethodInfo methodInfo2 = AccessTools.Method(typeof(AccessTools), "Method", new Type[4] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }, (Type[])null); if (methodInfo2 != null) { new Harmony("doodesch.polyfill.reflection").Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(ReflectionFallback), "MethodPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { log.Warning("[reflect] could not take over type lookups: " + ex.Message); } } private static bool TypeByNamePrefix(string name, ref Type __result) { __result = Resolve(name); return false; } private static void MethodPostfix(Type type, string name, Type[] parameters, Type[] generics, ref MethodInfo __result) { if (__result != null || type == null || string.IsNullOrEmpty(name) || parameters == null || generics != null) { return; } MethodInfo methodInfo = WidenedMatch(type, name, parameters); if (!(methodInfo == null)) { __result = methodInfo; Instance log = _log; if (log != null) { log.Msg($"[reflect] {type.Name}.{name} takes {methodInfo.GetParameters().Length} argument(s) now; answered the {parameters.Length}-argument lookup with it."); } } } private static MethodInfo WidenedMatch(Type type, string name, Type[] parameters) { for (Type type2 = type; type2 != null; type2 = type2.BaseType) { MethodInfo[] methods; try { methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } MethodInfo methodInfo = null; MethodInfo[] array = methods; foreach (MethodInfo methodInfo2 in array) { if (methodInfo2.Name != name) { continue; } ParameterInfo[] parameters2 = methodInfo2.GetParameters(); if (parameters2.Length <= parameters.Length) { continue; } bool flag = true; for (int j = 0; j < parameters.Length; j++) { if (parameters2[j].ParameterType != parameters[j]) { flag = false; break; } } if (flag) { if (methodInfo != null) { return null; } methodInfo = methodInfo2; } } if (methodInfo != null) { return methodInfo; } } return null; } private static Type Resolve(string name) { if (string.IsNullOrEmpty(name)) { return null; } lock (_answers) { if (_answers.TryGetValue(name, out var value)) { return value; } } Type type = null; try { type = Type.GetType(name, throwOnError: false); } catch { } if (type == null) { foreach (Assembly item in Loaded()) { try { type = item.GetType(name, throwOnError: false); } catch { } if (type != null) { break; } } } if (type == null) { type = BySimpleName(name); } if (type != null) { lock (_answers) { _answers[name] = type; } } return type; } private static IEnumerable Loaded() { Assembly[] assemblies; try { assemblies = AppDomain.CurrentDomain.GetAssemblies(); } catch { yield break; } Assembly[] array = assemblies; foreach (Assembly assembly in array) { string fullName; try { fullName = assembly.FullName; } catch { continue; } if (fullName == null || !fullName.StartsWith("Microsoft.VisualStudio", StringComparison.Ordinal)) { yield return assembly; } } } private static Type BySimpleName(string name) { if (name.IndexOf('.') >= 0 || name.IndexOf('+') >= 0 || name.IndexOf('/') >= 0) { return null; } foreach (Assembly item in Loaded()) { if (IsInterop(item)) { continue; } foreach (Type item2 in TypesOf(item)) { if (item2 != null && item2.Name == name) { return item2; } } } foreach (string item3 in GameBySimpleName(name)) { int num = item3.IndexOf('|'); if (num <= 0) { continue; } try { Type type = Assembly.Load(new AssemblyName(item3.Substring(0, num)))?.GetType(item3.Substring(num + 1), throwOnError: false); if (type != null) { return type; } } catch { } } return null; } private static IEnumerable TypesOf(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type t) => t != null); } catch { return Array.Empty(); } } private static bool IsInterop(Assembly assembly) { if (string.IsNullOrEmpty(_interop)) { return false; } string text; try { text = (assembly.IsDynamic ? null : assembly.Location); } catch { return true; } if (string.IsNullOrEmpty(text)) { return false; } try { return string.Equals(Path.GetDirectoryName(text), _interop.TrimEnd(Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase); } catch { return false; } } private static IReadOnlyList GameBySimpleName(string name) { if (!_gameIndexBuilt) { _gameIndexBuilt = true; _gameBySimpleName = BuildGameIndex(); } if (_gameBySimpleName == null || !_gameBySimpleName.TryGetValue(name, out var value)) { return Array.Empty(); } return value; } private static Dictionary> BuildGameIndex() { if (string.IsNullOrEmpty(_interop)) { return null; } try { using InteropIndex interopIndex = new InteropIndex(_interop, null, Array.Empty(), Array.Empty()); Dictionary> dictionary = new Dictionary>(StringComparer.Ordinal); foreach (string item in interopIndex.SimpleNames()) { foreach (TypeDefinition item2 in interopIndex.BySimpleName(item)) { ModuleDefinition module = ((MemberReference)item2).Module; object obj; if (module == null) { obj = null; } else { AssemblyDefinition assembly = module.Assembly; if (assembly == null) { obj = null; } else { AssemblyNameDefinition name = assembly.Name; obj = ((name != null) ? ((AssemblyNameReference)name).Name : null); } } string text = (string)obj; if (!string.IsNullOrEmpty(text)) { if (!dictionary.TryGetValue(item, out var value)) { value = (dictionary[item] = new List()); } value.Add(text + "|" + ((MemberReference)item2).FullName.Replace('/', '+')); } } } Instance log = _log; if (log != null) { log.Msg($"[reflect] read {dictionary.Count} game type name(s) from metadata for a name-only lookup."); } return dictionary; } catch (Exception ex) { Instance log2 = _log; if (log2 != null) { log2.Warning("[reflect] could not read the game's type names: " + ex.Message); } return null; } } } } namespace Polyfill.Core { internal static class AliasDb { private static VersionDb _db; private static GameVersion _game; internal static int Count => _db?.RenameCount ?? 0; internal static void Load(ILog log) { _game = GameVersionSource.Current; List<(string, IEnumerable)> list = new List<(string, IEnumerable)>(); list.AddRange(Embedded(log)); list.AddRange(Loose(log)); if (list.Count == 0) { log?.Msg("[alias] no version history is shipped with this build."); _db = VersionDb.Load(list); return; } _db = VersionDb.Load(list); foreach (string note in _db.Notes) { log?.Warning("[alias] " + note); } string text = _db.Gap(); if (text != null) { log?.Warning("[alias] the history has a hole in it: " + text + ". Renames across it are not followed."); } string value = ((_game.IsKnown && _db.Newest.IsKnown && _game < _db.Newest) ? $"; this game is {_game}, so anything newer is skipped." : "."); log?.Msg($"[alias] {_db.RenameCount} rename(s) over {_db.StepCount} build(s) of the game, {_db.Versions().First()} to {_db.Newest}{value}"); } private static IEnumerable<(string, IEnumerable)> Embedded(ILog log) { Assembly assembly = Assembly.GetExecutingAssembly(); string[] manifestResourceNames = assembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { string[] array = null; try { using Stream stream = assembly.GetManifestResourceStream(text); if (stream == null) { continue; } using StreamReader streamReader = new StreamReader(stream); string text2 = streamReader.ReadToEnd(); if (!text2.StartsWith("# polyfill-versiondb ", StringComparison.Ordinal)) { continue; } array = text2.Split('\n'); goto IL_00b0; } catch { goto IL_00b0; } IL_00b0: if (array != null) { yield return (Short(text), array); } } } private static IEnumerable<(string, IEnumerable)> Loose(ILog log) { string path; try { path = Path.Combine(PolyfillPaths.Folder(MelonEnvironment.UserDataDirectory), "versiondb"); } catch { yield break; } if (!Directory.Exists(path)) { yield break; } string[] files = Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories); foreach (string path2 in files) { string[] array = null; try { array = File.ReadAllLines(path2); } catch { } if (array != null && array.Length != 0) { log?.Msg("[alias] reading " + Path.GetFileName(path2) + " from UserData as well."); yield return (Path.GetFileName(path2), array); } } } private static string Short(string resourceName) { int num = resourceName.LastIndexOf(".txt", StringComparison.OrdinalIgnoreCase); if (num < 0) { return resourceName; } int num2 = resourceName.LastIndexOf('.', num - 1); if (num2 >= 0) { return resourceName.Substring(num2 + 1); } return resourceName; } internal static string Successor(string interopType, string wanted, int parameters, string gameVersion) { if (_db == null || interopType == null || wanted == null) { return null; } GameVersion game = ((gameVersion == null) ? _game : GameVersion.Parse(gameVersion)); string type = Game(interopType); string name = wanted; string text = ""; if (wanted.StartsWith("get_", StringComparison.Ordinal) || wanted.StartsWith("set_", StringComparison.Ordinal)) { text = wanted.Substring(0, 4); name = wanted.Substring(4); } if (text.Length == 0) { return _db.Successor("M", type, name, parameters, game); } string text2 = _db.Successor("P", type, name, 0, game); string text3 = _db.Successor("F", type, name, 0, game); if (text2 != null && text3 != null && text2 != text3) { return null; } string text4 = text2 ?? text3; if (text4 != null) { return text + text4; } return null; } internal static string RemovedIn(string interopType, string wanted, int parameters) { if (_db == null || interopType == null || wanted == null) { return null; } string type = Game(interopType); if (wanted.StartsWith("get_", StringComparison.Ordinal) || wanted.StartsWith("set_", StringComparison.Ordinal)) { string name = wanted.Substring(4); return _db.RemovedIn("P", type, name, 0) ?? _db.RemovedIn("F", type, name, 0); } return _db.RemovedIn("M", type, wanted, parameters); } internal static string Game(string interopType) { string text = interopType.Replace('/', '.'); if (text.StartsWith("Il2Cpp", StringComparison.Ordinal)) { text = text.Substring(6); } return text.TrimStart('.'); } } internal static class DumpIndex { internal sealed class Result { internal AssemblyDefinition Assembly; internal string Label; internal string Refusal; internal int Types; internal int Members; } private const string Prefix = "Il2Cpp"; private const int KnownFormat = 1; internal static Result Read(string path) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown Result result = new Result(); if (!File.Exists(path)) { result.Refusal = "there is no dump at " + path; return result; } string text = Path.GetFileName(path); int num = text.IndexOf(".api.txt", StringComparison.OrdinalIgnoreCase); if (num > 0) { text = text.Substring(0, num); } AssemblyDefinition val = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition(text, new Version(1, 0, 0, 0)), text, (ModuleKind)0); ModuleDefinition mainModule = val.MainModule; Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (string item in File.ReadLines(path)) { if (item.Length == 0) { continue; } if (item[0] == '#') { if (item.StartsWith("# apidump ", StringComparison.Ordinal)) { if (!int.TryParse(item.Substring(10).Trim(), out var result2) || result2 > 1) { result.Refusal = $"the dump says it is format {item.Substring(10).Trim()} and this reads {1}. Update the checker rather than trusting it."; return result; } } else if (item.StartsWith("# label=", StringComparison.Ordinal)) { result.Label = item.Substring(8).Trim(); } } else { switch (item[0]) { case 'T': Declare(mainModule, dictionary, item); break; case 'M': Member(mainModule, dictionary, item, method: true); break; case 'F': case 'P': Member(mainModule, dictionary, item, method: false); break; } } } foreach (TypeDefinition value in dictionary.Values) { mainModule.Types.Add(value); } result.Assembly = val; result.Types = dictionary.Count; foreach (TypeDefinition value2 in dictionary.Values) { result.Members += value2.Methods.Count + value2.Fields.Count; } return result; } private static void Declare(ModuleDefinition module, Dictionary types, string line) { string[] array = line.Split(' '); if (array.Length < 3) { return; } string[] array2 = array; foreach (string text in array2) { if (text.StartsWith("raw=", StringComparison.Ordinal)) { string text2 = text.Substring(4); if (text2.Length > 0) { EnsureExact(module, types, text2); return; } } } string text3 = null; for (int j = 2; j < array.Length; j++) { if (array[j].Length == 0) { continue; } bool flag; switch (array[j]) { case "sealed": case "static": case "struct": case "class": case "interface": case "enum": case "abstract": flag = true; break; default: flag = false; break; } if (!flag) { if (!array[j].StartsWith("base=", StringComparison.Ordinal)) { text3 = array[j]; } break; } } if (text3 != null) { Ensure(module, types, text3); } } private static void Member(ModuleDefinition module, Dictionary types, string line, bool method) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown int num = line.IndexOf("::", StringComparison.Ordinal); if (num < 0) { return; } int num2 = line.LastIndexOf(' ', num) + 1; string gameName = line.Substring(num2, num - num2); TypeDefinition val = Ensure(module, types, gameName); if (val == null) { return; } string text = line.Substring(num + 2); int num3 = text.LastIndexOf(" : ", StringComparison.Ordinal); string gameName2 = ((num3 < 0) ? "System.Void" : Cut(text.Substring(num3 + 3))); string text2 = ((num3 < 0) ? text : text.Substring(0, num3)); if (!method) { string text3 = Cut(text2); if (text3.Length != 0) { val.Fields.Add(new FieldDefinition(text3, (FieldAttributes)6, Reference(module, gameName2))); } return; } int num4 = text2.IndexOf('('); if (num4 < 0) { return; } int num5 = text2.LastIndexOf(')'); if (num5 < num4) { return; } MethodDefinition val2 = new MethodDefinition(text2.Substring(0, num4), (MethodAttributes)6, Reference(module, gameName2)); string text4 = text2.Substring(num4 + 1, num5 - num4 - 1).Trim(); List list = ParameterNames(line); if (text4.Length > 0) { List list2 = Split(text4); for (int i = 0; i < list2.Count; i++) { string text5 = ((i < list.Count) ? list[i] : ("arg" + i)); ((MethodReference)val2).Parameters.Add(new ParameterDefinition(text5, (ParameterAttributes)0, Reference(module, list2[i]))); } } val.Methods.Add(val2); } private static List ParameterNames(string line) { List list = new List(); int num = line.IndexOf(" pnames=", StringComparison.Ordinal); if (num < 0) { return list; } string text = line.Substring(num + 8); int num2 = text.IndexOf(' '); if (num2 > 0) { text = text.Substring(0, num2); } string[] array = text.Split(','); foreach (string text2 in array) { if (text2.Length > 0) { list.Add(text2); } } return list; } private static List Split(string list) { List list2 = new List(); int num = 0; int num2 = 0; for (int i = 0; i < list.Length; i++) { switch (list[i]) { case '<': case '[': num++; break; case '>': case ']': num--; break; case ',': if (num == 0) { list2.Add(list.Substring(num2, i - num2).Trim()); num2 = i + 1; } break; } } if (num2 < list.Length) { list2.Add(list.Substring(num2).Trim()); } return list2; } private static string Cut(string value) { int num = value.IndexOf(' '); return ((num < 0) ? value : value.Substring(0, num)).Trim(); } private static TypeDefinition Ensure(ModuleDefinition module, Dictionary types, string gameName) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown if (string.IsNullOrEmpty(gameName)) { return null; } string text = Interop(gameName); if (types.TryGetValue(text, out var value)) { return value; } int num = text.LastIndexOf('.'); string obj = ((num < 0) ? "" : text.Substring(0, num)); string text2 = ((num < 0) ? text : text.Substring(num + 1)); return types[text] = new TypeDefinition(obj, text2, (TypeAttributes)1, module.TypeSystem.Object); } private static string Interop(string gameName) { if (gameName.StartsWith("Il2Cpp", StringComparison.Ordinal)) { return gameName; } if (gameName.StartsWith("System.", StringComparison.Ordinal)) { return gameName; } if (gameName.StartsWith("UnityEngine.", StringComparison.Ordinal)) { return gameName; } if (!gameName.Contains('.')) { return "Il2Cpp." + gameName; } return "Il2Cpp" + gameName; } private static TypeDefinition EnsureExact(ModuleDefinition module, Dictionary types, string full) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (types.TryGetValue(full, out var value)) { return value; } int num = full.LastIndexOf('.'); return types[full] = new TypeDefinition((num < 0) ? "" : full.Substring(0, num), (num < 0) ? full : full.Substring(num + 1), (TypeAttributes)1, module.TypeSystem.Object); } private static TypeReference Reference(ModuleDefinition module, string gameName) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if (string.IsNullOrEmpty(gameName)) { return module.TypeSystem.Object; } string text = Interop(gameName.TrimEnd('&', '*')); int num = text.LastIndexOf('.'); string obj = ((num < 0) ? "" : text.Substring(0, num)); string text2 = ((num < 0) ? text : text.Substring(num + 1)); return new TypeReference(obj, text2, module, module.TypeSystem.CoreLibrary); } } internal static class FacadeTypes { internal sealed class Member { internal string Name; internal string Returns; internal string[] Takes; internal Func Emit; } internal static TypeDefinition TryAdd(ModuleDefinition module, string oldNamespace, string oldName, string targetFullName, IEnumerable members, out string refusal) { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown refusal = null; TypeDefinition type = module.GetType(targetFullName); if (type == null) { refusal = "the type it stands in for is not in this assembly"; return null; } TypeReference baseType = type.BaseType; GenericInstanceType val = (GenericInstanceType)(object)((baseType is GenericInstanceType) ? baseType : null); if (val == null || val.GenericArguments.Count != 1 || !string.Equals(((MemberReference)val.GenericArguments[0]).FullName, ((MemberReference)type).FullName, StringComparison.Ordinal)) { refusal = ((MemberReference)type).FullName + " does not derive from a generic closed over itself"; return null; } TypeDefinition val2 = PointerStore(module); if (val2 == null) { refusal = "Il2CppClassPointerStore is not referenced by this assembly"; return null; } FieldDefinition val3 = ((IEnumerable)val2.Fields).FirstOrDefault((Func)((FieldDefinition f) => ((MemberReference)f).Name == "NativeClassPtr")); if (val3 == null) { refusal = "Il2CppClassPointerStore has no NativeClassPtr"; return null; } TypeDefinition obj = ((TypeReference)val).Resolve(); MethodDefinition val4 = ((obj != null) ? ((IEnumerable)obj.Methods).FirstOrDefault((Func)((MethodDefinition m) => m.IsConstructor && !m.IsStatic && ((MethodReference)m).Parameters.Count == 1 && (int)((ParameterReference)((MethodReference)m).Parameters[0]).ParameterType.MetadataType == 24)) : null); if (val4 == null) { refusal = ((MemberReference)val).Name + " has no pointer constructor to build on"; return null; } TypeDefinition val5 = new TypeDefinition(oldNamespace, oldName, (TypeAttributes)1048577, module.TypeSystem.Object); module.Types.Add(val5); GenericInstanceType val6 = new GenericInstanceType(module.ImportReference(((TypeSpecification)val).ElementType)); val6.GenericArguments.Add((TypeReference)(object)val5); val5.BaseType = (TypeReference)(object)val6; AddPointerConstructor(module, val5, val6, val4); AddClassPointerAlias(module, val5, val2, val3, type); foreach (Member item in members ?? Enumerable.Empty()) { if (!AddAnswer(module, val5, type, item, out refusal)) { module.Types.Remove(val5); return null; } } return val5; } private static void AddPointerConstructor(ModuleDefinition module, TypeDefinition facade, GenericInstanceType closedBase, MethodDefinition baseConstructor) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = new MethodDefinition(".ctor", (MethodAttributes)6278, module.TypeSystem.Void); ((MethodReference)val).Parameters.Add(new ParameterDefinition("pointer", (ParameterAttributes)0, module.TypeSystem.IntPtr)); ILProcessor iLProcessor = val.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Call, module.ImportReference(ShadowTypes.On(closedBase, baseConstructor))); iLProcessor.Emit(OpCodes.Ret); facade.Methods.Add(val); } private static void AddClassPointerAlias(ModuleDefinition module, TypeDefinition facade, TypeDefinition store, FieldDefinition nativePointer, TypeDefinition target) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) MethodDefinition val = new MethodDefinition(".cctor", (MethodAttributes)6289, module.TypeSystem.Void); ILProcessor iLProcessor = val.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldsfld, Closed(module, store, nativePointer, (TypeReference)(object)target)); iLProcessor.Emit(OpCodes.Stsfld, Closed(module, store, nativePointer, (TypeReference)(object)facade)); iLProcessor.Emit(OpCodes.Ret); facade.Methods.Add(val); } private static FieldReference Closed(ModuleDefinition module, TypeDefinition store, FieldDefinition field, TypeReference argument) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown GenericInstanceType val = new GenericInstanceType(module.ImportReference((TypeReference)(object)store)); val.GenericArguments.Add(module.ImportReference(argument)); return new FieldReference(((MemberReference)field).Name, module.ImportReference(((FieldReference)field).FieldType), (TypeReference)(object)val); } private static bool AddAnswer(ModuleDefinition module, TypeDefinition facade, TypeDefinition target, Member member, out string refusal) { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Invalid comparison between Unknown and I4 //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) refusal = null; if (member.Emit != null) { MethodDefinition val; try { val = member.Emit(module, facade, target); } catch (Exception ex) { refusal = "the rule for " + member.Name + " failed on this build: " + ex.Message; return false; } if (val == null) { refusal = "the rule for " + member.Name + " needs members this build has not got"; return false; } if (!Matches(val, member, out var mismatch)) { refusal = "the rule for " + member.Name + " built " + mismatch; return false; } facade.Methods.Add(val); return true; } TypeReference val2 = module.TypeSystem.Void; if (member.Returns != null) { TypeReference val3 = (TypeReference)(((object)module.GetType(member.Returns)) ?? ((object)Builtin(module, member.Returns))); if (val3 == null) { refusal = member.Returns + ", which " + member.Name + " gives back, is not in this assembly"; return false; } val2 = module.ImportReference(val3); } MethodDefinition val4 = new MethodDefinition(member.Name, (MethodAttributes)134, val2); string[] array = member.Takes ?? Array.Empty(); foreach (string text in array) { TypeReference val5 = (TypeReference)(((object)module.GetType(text)) ?? ((object)Builtin(module, text))); if (val5 == null) { refusal = text + ", which " + member.Name + " takes, is not in this assembly"; return false; } ((MethodReference)val4).Parameters.Add(new ParameterDefinition(module.ImportReference(val5))); } ILProcessor iLProcessor = val4.Body.GetILProcessor(); if ((int)val2.MetadataType != 1) { if (val2.IsValueType) { iLProcessor.Emit(OpCodes.Ldc_I4_0); } else { iLProcessor.Emit(OpCodes.Ldnull); } } iLProcessor.Emit(OpCodes.Ret); facade.Methods.Add(val4); return true; } private static bool Matches(MethodDefinition built, Member member, out string mismatch) { mismatch = null; if (((MemberReference)built).Name != member.Name) { mismatch = "a method called " + ((MemberReference)built).Name; return false; } string text = member.Returns ?? "System.Void"; if (((MemberReference)((MethodReference)built).ReturnType).FullName != text) { mismatch = "one returning " + ((MemberReference)((MethodReference)built).ReturnType).FullName + ", not " + text; return false; } string[] array = member.Takes ?? Array.Empty(); if (((MethodReference)built).Parameters.Count != array.Length) { mismatch = $"one taking {((MethodReference)built).Parameters.Count} argument(s), not {array.Length}"; return false; } for (int i = 0; i < array.Length; i++) { if (((MemberReference)((ParameterReference)((MethodReference)built).Parameters[i]).ParameterType).FullName != array[i]) { mismatch = $"argument {i + 1} as {((MemberReference)((ParameterReference)((MethodReference)built).Parameters[i]).ParameterType).FullName}, not {array[i]}"; return false; } } return true; } private static TypeReference Builtin(ModuleDefinition module, string fullName) { return (TypeReference)(fullName switch { "System.String" => module.TypeSystem.String, "System.Boolean" => module.TypeSystem.Boolean, "System.Int32" => module.TypeSystem.Int32, "System.Single" => module.TypeSystem.Single, _ => null, }); } private static TypeDefinition PointerStore(ModuleDefinition module) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = module.AssemblyReferences.GetEnumerator(); try { while (enumerator.MoveNext()) { AssemblyNameReference current = enumerator.Current; AssemblyDefinition val = null; try { IAssemblyResolver assemblyResolver = module.AssemblyResolver; val = ((assemblyResolver != null) ? assemblyResolver.Resolve(current) : null); } catch { } if (val == null) { continue; } Enumerator enumerator2 = val.MainModule.Types.GetEnumerator(); try { while (enumerator2.MoveNext()) { TypeDefinition current2 = enumerator2.Current; if (((MemberReference)current2).Name == "Il2CppClassPointerStore`1" && ((TypeReference)current2).HasGenericParameters) { return current2; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } } internal sealed class GeneratorIdentity { internal string GameAssemblyHash; internal string UnityVersion; internal string DumperVersion; internal string DumperScrsVersion; internal string Loader; internal bool IsKnown => !string.IsNullOrEmpty(GameAssemblyHash); internal string Digest() { string text = GameAssemblyHash ?? ""; if (text.Length > 16) { text = text.Substring(0, 16); } return $"{text}/{UnityVersion}/{DumperVersion}/{DumperScrsVersion}/{Loader}"; } internal static GeneratorIdentity Read() { GeneratorIdentity generatorIdentity = new GeneratorIdentity { Loader = MelonLoaderVersion() }; string text = ConfigPath(); if (text == null || !File.Exists(text)) { return generatorIdentity; } try { string[] array = File.ReadAllLines(text); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num > 0) { string text3 = text2.Substring(0, num).Trim(); string text4 = text2.Substring(num + 1).Trim().Trim('"'); switch (text3) { case "GameAssemblyHash": generatorIdentity.GameAssemblyHash = text4; break; case "UnityVersion": generatorIdentity.UnityVersion = text4; break; case "DumperVersion": generatorIdentity.DumperVersion = text4; break; case "DumperSCRSVersion": generatorIdentity.DumperScrsVersion = text4; break; } } } } catch { } return generatorIdentity; } internal static string ConfigPath() { try { string melonLoaderDirectory = MelonEnvironment.MelonLoaderDirectory; if (string.IsNullOrEmpty(melonLoaderDirectory)) { return null; } return Path.Combine(melonLoaderDirectory, "Dependencies", "Il2CppAssemblyGenerator", "Config.cfg"); } catch { return null; } } private static string MelonLoaderVersion() { try { return typeof(MelonPlugin).Assembly.GetName().Version?.ToString() ?? "?"; } catch { return "?"; } } } internal static class HarmonyTargets { private enum Match { Yes, No, Unknown } private sealed class Spec { internal TypeReference DeclaringType; internal string TypeName; internal string MethodName; internal List ArgumentTypes; internal int? MethodType; } private const string PatchAttribute = "HarmonyLib.HarmonyPatch"; private static string Decorate(string name, int? methodType) { return methodType switch { 1 => "get_" + name, 2 => "set_" + name, 3 => ".ctor", 4 => ".cctor", _ => name, }; } internal static void Check(ModuleDefinition module, InteropIndex index, ModReport report) { //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) foreach (TypeDefinition type in module.GetTypes()) { Spec spec = Read(type.CustomAttributes); bool flag = spec != null; if (flag && spec.MethodName != null) { Verify(spec, ((MemberReference)type).FullName, index, report, PatchMethods(type)); } if (!type.HasMethods) { continue; } Enumerator enumerator2 = type.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { MethodDefinition current2 = enumerator2.Current; Spec spec2 = Read(current2.CustomAttributes); if (spec2 != null) { Spec spec3 = Merge(spec, spec2); if (spec3.MethodName != null && (!flag || spec2.DeclaringType != null || spec2.MethodName != null)) { Verify(spec3, ((MemberReference)type).FullName + "." + ((MemberReference)current2).Name, index, report, new List { current2 }); } } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } } private static void Verify(Spec spec, string site, InteropIndex index, ModReport report, List patches) { report.HarmonyTargetsChecked++; TypeDefinition val = null; if (spec.DeclaringType != null) { val = Triage.Resolve(spec.DeclaringType, index); } else if (spec.TypeName != null) { foreach (TypeDefinition item in index.BySimpleName(SimpleNameOf(spec.TypeName))) { if (((MemberReference)item).FullName == spec.TypeName) { val = item; break; } } } if (val == null) { TypeReference declaringType = spec.DeclaringType; string text = ((declaringType != null) ? ((MemberReference)declaringType).FullName : null) ?? spec.TypeName ?? "?"; TypeReference declaringType2 = spec.DeclaringType; object obj; if (declaringType2 == null) { obj = null; } else { IMetadataScope scope = declaringType2.Scope; obj = ((scope != null) ? scope.Name : null); } if (obj == null) { obj = ""; } string text2 = (string)obj; TypeRename typeRename = Registry.FindType(text2, text); TypeDefinition val2 = ((typeRename == null) ? null : index.FindType(text2, typeRename.NewFullName)); if (val2 != null) { Verify(spec, site, index, report, val2, text, patches); return; } IReadOnlyList readOnlyList = index.BySimpleName(SimpleNameOf(text)); if (RenamedTypes.IsStandIn(text) && readOnlyList.Count == 1) { Verify(spec, site, index, report, readOnlyList[0], text, patches); return; } report.Findings.Add(new Finding { Kind = "harmony-target", Scope = text2, Symbol = text + "::" + spec.MethodName, Reason = "the patched type does not exist here, so this patch will not apply", Hint = ((readOnlyList.Count == 1) ? ((MemberReference)readOnlyList[0]).FullName : ""), Site = site }); } else { Verify(spec, site, index, report, val, null, patches); } } private static List PatchMethods(TypeDefinition type) { //IL_0016: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (!type.HasMethods) { return list; } Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; bool flag; switch (((MemberReference)current).Name) { case "Prefix": case "Postfix": case "Finalizer": flag = true; break; default: flag = false; break; } bool flag2 = flag; if (!flag2 && current.HasCustomAttributes) { Enumerator enumerator2 = current.CustomAttributes.GetEnumerator(); try { while (enumerator2.MoveNext()) { TypeReference attributeType = enumerator2.Current.AttributeType; switch ((attributeType != null) ? ((MemberReference)attributeType).FullName : null) { case "HarmonyLib.HarmonyPrefix": case "HarmonyLib.HarmonyPostfix": case "HarmonyLib.HarmonyFinalizer": flag = true; break; default: flag = false; break; } if (flag) { flag2 = true; break; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } if (flag2) { list.Add(current); } } return list; } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } private static Match Same(List wanted, MethodDefinition method) { if (wanted.Count != ((MethodReference)method).Parameters.Count) { return Match.No; } for (int i = 0; i < wanted.Count; i++) { TypeReference obj = wanted[i]; string text = ((obj != null) ? ((MemberReference)obj).FullName : null); TypeReference parameterType = ((ParameterReference)((MethodReference)method).Parameters[i]).ParameterType; string text2 = ((parameterType != null) ? ((MemberReference)parameterType).FullName : null); if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2)) { return Match.Unknown; } if (text != text2) { return Match.No; } } return Match.Yes; } private static IEnumerable Spelled(List types) { foreach (TypeReference type in types) { yield return ((type != null) ? ((MemberReference)type).FullName : null) ?? "?"; } } private static void Verify(Spec spec, string site, InteropIndex index, ModReport report, TypeDefinition declaring, string under, List patches) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) string text = Decorate(spec.MethodName, spec.MethodType); int num = spec.ArgumentTypes?.Count ?? (-1); MethodDefinition val = null; MethodDefinition val2 = null; int num2 = 0; int num3 = 0; Enumerator enumerator = declaring.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name != text || (num >= 0 && ((MethodReference)current).Parameters.Count != num)) { continue; } num2++; if (val == null) { val = current; } if (spec.ArgumentTypes == null) { continue; } switch (Same(spec.ArgumentTypes, current)) { case Match.Yes: if (val2 == null) { val2 = current; } num3++; break; case Match.No: num3++; break; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (spec.ArgumentTypes != null && num2 > 0 && num3 == num2 && val2 == null) { List findings = report.Findings; Finding finding = new Finding { Kind = "harmony-target" }; Finding finding2 = finding; ModuleDefinition module = ((MemberReference)declaring).Module; object obj; if (module == null) { obj = null; } else { AssemblyDefinition assembly = module.Assembly; if (assembly == null) { obj = null; } else { AssemblyNameDefinition name = assembly.Name; obj = ((name != null) ? ((AssemblyNameReference)name).Name : null); } } if (obj == null) { obj = ""; } finding2.Scope = (string)obj; finding.Symbol = (under ?? ((MemberReference)declaring).FullName) + "::" + text + "(" + string.Join(", ", Spelled(spec.ArgumentTypes)) + ")"; finding.Reason = $"this build has {num2} method(s) called {text} with that many parameters " + "and none of them takes those types, so the patch resolves nothing. Harmony throws out of PatchAll, which costs this patch class and every one after it"; finding.Site = site; findings.Add(finding); return; } if (val2 != null) { val = val2; } if (num2 > 1 && num < 0) { List findings2 = report.Findings; Finding obj2 = new Finding { Kind = "harmony-target" }; ModuleDefinition module2 = ((MemberReference)declaring).Module; object obj3; if (module2 == null) { obj3 = null; } else { AssemblyDefinition assembly2 = module2.Assembly; if (assembly2 == null) { obj3 = null; } else { AssemblyNameDefinition name2 = assembly2.Name; obj3 = ((name2 != null) ? ((AssemblyNameReference)name2).Name : null); } } if (obj3 == null) { obj3 = ""; } obj2.Scope = (string)obj3; obj2.Symbol = (under ?? ((MemberReference)declaring).FullName) + "::" + text; obj2.Reason = $"this build has {num2} methods called {text} and the patch names no " + "parameters, so Harmony cannot tell which one is meant. It throws out of PatchAll, which costs this patch class and every one after it"; obj2.Site = site; findings2.Add(obj2); return; } if (val != null) { Names(val, patches, site, report); return; } for (TypeDefinition val3 = Base(declaring, index); val3 != null; val3 = Base(val3, index)) { enumerator = val3.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current2 = enumerator.Current; if (((MemberReference)current2).Name == text && (num < 0 || ((MethodReference)current2).Parameters.Count == num)) { Names(current2, patches, site, report); return; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } string text2 = RenamedMethods.Successor(under ?? ((MemberReference)declaring).FullName, text); if (text2 != null) { enumerator = declaring.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current3 = enumerator.Current; if (((MemberReference)current3).Name == text2 && (num < 0 || ((MethodReference)current3).Parameters.Count == num)) { Names(current3, patches, site, report); return; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } for (TypeDefinition val4 = Base(declaring, index); val4 != null; val4 = Base(val4, index)) { enumerator = val4.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current4 = enumerator.Current; if (((MemberReference)current4).Name == text2 && (num < 0 || ((MethodReference)current4).Parameters.Count == num)) { Names(current4, patches, site, report); return; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } } ModuleDefinition module3 = ((MemberReference)declaring).Module; object obj4; if (module3 == null) { obj4 = null; } else { AssemblyDefinition assembly3 = module3.Assembly; if (assembly3 == null) { obj4 = null; } else { AssemblyNameDefinition name3 = assembly3.Name; obj4 = ((name3 != null) ? ((AssemblyNameReference)name3).Name : null); } } if (obj4 == null) { obj4 = ""; } string text3 = (string)obj4; string text4 = under ?? ((MemberReference)declaring).FullName; Bridge bridge = Registry.FindByName(text3, text4, text, num); if (bridge != null) { string repairKey = Triage.Request(new InteropAugmentor.MemberForward { InAssembly = bridge.Assembly, DeclaringType = bridge.DeclaringType, OldName = bridge.OldName, NewName = null, ParameterCount = bridge.ParameterCount, ParameterTypes = bridge.ParameterTypes, Rule = "curated" }); report.Findings.Add(new Finding { Kind = "harmony-target", Scope = text3, Symbol = text4 + "::" + text, Reason = "the patched method is gone", Hint = "hand-written rule: " + bridge.Because, RepairKey = repairKey, Site = site }); return; } if (GrownOverloads.Doubled(text4, text)) { report.Findings.Add(new Finding { Kind = "harmony-target", Scope = text3, Symbol = text4 + "::" + text, Reason = "the signature this patch names is gone; Polyfill puts it back and moves the patch onto the method the game calls (`polyfillfixes` lists it as patches-on-grown-overloads)", Site = site }); return; } List list = NameHeuristics.ForMethod(declaring, text, null); TypeDefinition val5 = ((list.Count > 0) ? declaring : null); if (list.Count == 0) { for (TypeDefinition val6 = Base(declaring, index); val6 != null; val6 = Base(val6, index)) { list = NameHeuristics.ForMethod(val6, text, null); if (list.Count > 0) { val5 = val6; break; } } } string text5 = ((val5 == null || val5 == declaring) ? "" : (" on " + ((MemberReference)val5).Name)); report.Findings.Add(new Finding { Kind = "harmony-target", Scope = text3, Symbol = text4 + "::" + text, Reason = ((list.Count > 1) ? $"the patched method is gone; {list.Count} members could be meant, so none is chosen" : ((under != null) ? $"the type is put back as {((MemberReference)declaring).Name}, which has no {text} to patch" : "the patched method is gone, so this patch will not apply")), Hint = ((list.Count == 1) ? (list[0].NewName + text5 + " [" + list[0].Rule + "]") : ""), Site = site }); } private static void Names(MethodDefinition target, List patches, string site, ModReport report) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (patches == null || patches.Count == 0 || target == null) { return; } TypeDefinition declaringType = target.DeclaringType; string text = ((declaringType != null) ? ((MemberReference)declaringType).FullName : null); if (text == null) { return; } foreach (RenamedParameters.Entry item in RenamedParameters.For(text, ((MemberReference)target).Name, ((MethodReference)target).Parameters.Count)) { bool flag = false; bool flag2 = false; foreach (MethodDefinition patch in patches) { Enumerator enumerator3 = ((MethodReference)patch).Parameters.GetEnumerator(); try { while (enumerator3.MoveNext()) { ParameterDefinition current2 = enumerator3.Current; if (((ParameterReference)current2).Name != null && !((ParameterReference)current2).Name.StartsWith("__", StringComparison.Ordinal)) { if (((ParameterReference)current2).Name == item.OldName) { flag = true; } if (((ParameterReference)current2).Name == item.NewName) { flag2 = true; } } } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } } if (!flag) { continue; } Finding finding; if (flag2) { List findings = report.Findings; finding = new Finding { Kind = "harmony-target" }; Finding finding2 = finding; ModuleDefinition module = ((MemberReference)target).Module; object obj; if (module == null) { obj = null; } else { AssemblyDefinition assembly = module.Assembly; if (assembly == null) { obj = null; } else { AssemblyNameDefinition name = assembly.Name; obj = ((name != null) ? ((AssemblyNameReference)name).Name : null); } } if (obj == null) { obj = ""; } finding2.Scope = (string)obj; finding.Symbol = text + "::" + ((MemberReference)target).Name + "(" + item.NewName + ")"; finding.Reason = $"this patch asks for the argument under both names, so neither can be put back; 0.4.6 renamed {item.OldName} to {item.NewName}"; finding.Site = site; findings.Add(finding); continue; } InteropAugmentor.ParameterRename parameterRename = new InteropAugmentor.ParameterRename(); ModuleDefinition module2 = ((MemberReference)target).Module; object inAssembly; if (module2 == null) { inAssembly = null; } else { AssemblyDefinition assembly2 = module2.Assembly; if (assembly2 == null) { inAssembly = null; } else { AssemblyNameDefinition name2 = assembly2.Name; inAssembly = ((name2 != null) ? ((AssemblyNameReference)name2).Name : null); } } parameterRename.InAssembly = (string)inAssembly; parameterRename.DeclaringType = text; parameterRename.Method = ((MemberReference)target).Name; parameterRename.ParameterCount = ((MethodReference)target).Parameters.Count; parameterRename.Index = item.Index; parameterRename.Name = item.OldName; parameterRename.WasCalled = item.NewName; parameterRename.Because = item.Because; string repairKey = Triage.RequestRename(parameterRename); List findings2 = report.Findings; finding = new Finding { Kind = "harmony-target" }; Finding finding3 = finding; ModuleDefinition module3 = ((MemberReference)target).Module; object obj2; if (module3 == null) { obj2 = null; } else { AssemblyDefinition assembly3 = module3.Assembly; if (assembly3 == null) { obj2 = null; } else { AssemblyNameDefinition name3 = assembly3.Name; obj2 = ((name3 != null) ? ((AssemblyNameReference)name3).Name : null); } } if (obj2 == null) { obj2 = ""; } finding3.Scope = (string)obj2; finding.Symbol = text + "::" + ((MemberReference)target).Name + "(" + item.OldName + ")"; finding.Reason = "the method is here and its argument was renamed to " + item.NewName + ", which Harmony matches on"; finding.Hint = "hand-written rule: " + item.Because; finding.RepairKey = repairKey; finding.Site = site; findings2.Add(finding); } } private static TypeDefinition Base(TypeDefinition type, InteropIndex index) { if (((type != null) ? type.BaseType : null) != null) { return Triage.Resolve(Triage.Root(type.BaseType), index); } return null; } private static string SimpleNameOf(string fullName) { if (string.IsNullOrEmpty(fullName)) { return fullName; } int num = fullName.LastIndexOfAny(new char[2] { '/', '+' }); if (num >= 0) { return fullName.Substring(num + 1); } int num2 = fullName.LastIndexOf('.'); if (num2 < 0) { return fullName; } return fullName.Substring(num2 + 1); } private static Spec Merge(Spec outer, Spec inner) { if (outer == null) { return inner; } return new Spec { DeclaringType = (inner.DeclaringType ?? outer.DeclaringType), TypeName = (inner.TypeName ?? outer.TypeName), MethodName = (inner.MethodName ?? outer.MethodName), ArgumentTypes = (inner.ArgumentTypes ?? outer.ArgumentTypes), MethodType = (inner.MethodType ?? outer.MethodType) }; } private static Spec Read(Collection attributes) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) Spec spec = null; Enumerator enumerator = attributes.GetEnumerator(); try { while (enumerator.MoveNext()) { CustomAttribute current = enumerator.Current; TypeReference attributeType = current.AttributeType; if (((attributeType != null) ? ((MemberReference)attributeType).FullName : null) != "HarmonyLib.HarmonyPatch") { continue; } if (spec == null) { spec = new Spec(); } List list = new List(); Enumerator enumerator2 = current.ConstructorArguments.GetEnumerator(); try { while (enumerator2.MoveNext()) { CustomAttributeArgument current2 = enumerator2.Current; object value = ((CustomAttributeArgument)(ref current2)).Value; TypeReference val = (TypeReference)((value is TypeReference) ? value : null); if (val == null) { if (!(value is string text)) { if (!(value is CustomAttributeArgument[] array)) { if (!(value is int num)) { continue; } int num2 = num; TypeReference type = ((CustomAttributeArgument)(ref current2)).Type; if (((type != null) ? ((MemberReference)type).Name : null) == "MethodType") { Spec spec2 = spec; int valueOrDefault = spec2.MethodType.GetValueOrDefault(); if (!spec2.MethodType.HasValue) { valueOrDefault = num2; spec2.MethodType = valueOrDefault; } } continue; } CustomAttributeArgument[] array2 = array; if (IsTypeArray(((CustomAttributeArgument)(ref current2)).Type)) { Spec spec2 = spec; if (spec2.ArgumentTypes == null) { spec2.ArgumentTypes = TypesIn(array2); } } } else { string item = text; list.Add(item); } } else { TypeReference declaringType = val; Spec spec2 = spec; if (spec2.DeclaringType == null) { spec2.DeclaringType = declaringType; } } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } if (list.Count == 1) { Spec spec2 = spec; if (spec2.MethodName == null) { spec2.MethodName = list[0]; } } else if (list.Count >= 2) { Spec spec2 = spec; if (spec2.TypeName == null) { spec2.TypeName = list[0]; } spec2 = spec; if (spec2.MethodName == null) { spec2.MethodName = list[1]; } } Enumerator enumerator3 = current.Properties.GetEnumerator(); try { while (enumerator3.MoveNext()) { CustomAttributeNamedArgument current3 = enumerator3.Current; Apply(spec, current3); } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } enumerator3 = current.Fields.GetEnumerator(); try { while (enumerator3.MoveNext()) { CustomAttributeNamedArgument current4 = enumerator3.Current; Apply(spec, current4); } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } } return spec; } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } private static void Apply(Spec spec, CustomAttributeNamedArgument named) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) CustomAttributeArgument argument; switch (((CustomAttributeNamedArgument)(ref named)).Name) { case "declaringType": { argument = ((CustomAttributeNamedArgument)(ref named)).Argument; object value = ((CustomAttributeArgument)(ref argument)).Value; TypeReference val = (TypeReference)((value is TypeReference) ? value : null); if (val != null) { Spec spec2 = spec; if (spec2.DeclaringType == null) { spec2.DeclaringType = val; } } break; } case "methodName": argument = ((CustomAttributeNamedArgument)(ref named)).Argument; if (((CustomAttributeArgument)(ref argument)).Value is string methodName) { Spec spec2 = spec; if (spec2.MethodName == null) { spec2.MethodName = methodName; } } break; case "methodType": argument = ((CustomAttributeNamedArgument)(ref named)).Argument; if (((CustomAttributeArgument)(ref argument)).Value is int num) { Spec spec2 = spec; int valueOrDefault = spec2.MethodType.GetValueOrDefault(); if (!spec2.MethodType.HasValue) { valueOrDefault = num; spec2.MethodType = valueOrDefault; } } break; case "argumentTypes": argument = ((CustomAttributeNamedArgument)(ref named)).Argument; if (((CustomAttributeArgument)(ref argument)).Value is CustomAttributeArgument[] array) { Spec spec2 = spec; if (spec2.ArgumentTypes == null) { spec2.ArgumentTypes = TypesIn(array); } } break; } } private static bool IsTypeArray(TypeReference arrayType) { TypeReference obj = ((arrayType is ArrayType) ? arrayType : null); object obj2; if (obj == null) { obj2 = null; } else { TypeReference elementType = ((TypeSpecification)obj).ElementType; obj2 = ((elementType != null) ? ((MemberReference)elementType).FullName : null); } return (string?)obj2 == "System.Type"; } private static List TypesIn(CustomAttributeArgument[] array) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) List list = new List(); for (int i = 0; i < array.Length; i++) { CustomAttributeArgument val = array[i]; object value = ((CustomAttributeArgument)(ref val)).Value; TypeReference val2 = (TypeReference)((value is TypeReference) ? value : null); if (val2 != null) { list.Add(val2); } } return list; } } internal static class InteropAugmentor { internal sealed class TypeForward { internal string InAssembly; internal string Namespace; internal string Name; internal string TargetAssembly; internal string TargetFullName; internal string NestedIn; internal bool ByNativeClass; internal List Answers; internal string Key => "T|" + InAssembly + "!" + (NestedIn ?? Namespace) + "." + Name; } internal sealed class MemberForward { internal string InAssembly; internal string DeclaringType; internal string OldName; internal string NewName; internal int ParameterCount; internal string Rule; internal string[] ParameterTypes; internal bool SameNameNewReturn; internal string Key => "M|" + InAssembly + "!" + DeclaringType + "::" + OldName + "/" + ParameterCount + ((ParameterTypes == null) ? "" : ("(" + string.Join(",", ParameterTypes) + ")")); } internal sealed class ParameterRename { internal string InAssembly; internal string DeclaringType; internal string Method; internal int ParameterCount; internal int Index; internal string Name; internal string WasCalled; internal string Because; internal string Key => "P|" + InAssembly + "!" + DeclaringType + "::" + Method + "/" + ParameterCount + "#" + Index; } internal sealed class Result { internal int Written; internal readonly List Applied = new List(); internal readonly List Refused = new List(); internal readonly List Stamped = new List(); internal readonly Dictionary Outcomes = new Dictionary(StringComparer.Ordinal); internal void Record(string key, string outcome, string detail = null) { if (key != null) { Outcomes[key] = (string.IsNullOrEmpty(detail) ? outcome : (outcome + ":" + detail)); } } } internal const string BackupSuffix = ".polyfill-orig"; internal static Result Apply(string interopDirectory, List types, List members, List renames, InteropOriginals originals, ILog log) { Result result = new Result(); if (types.Count == 0 && members.Count == 0 && renames.Count == 0) { return result; } SortedSet sortedSet = new SortedSet(StringComparer.OrdinalIgnoreCase); foreach (TypeForward type in types) { sortedSet.Add(type.InAssembly); } foreach (MemberForward member in members) { sortedSet.Add(member.InAssembly); } foreach (ParameterRename rename in renames) { if (rename.InAssembly != null) { sortedSet.Add(rename.InAssembly); } } foreach (string item in sortedSet) { List list = new List(); foreach (TypeForward type2 in types) { if (string.Equals(type2.InAssembly, item, StringComparison.OrdinalIgnoreCase)) { list.Add(type2); } } List list2 = new List(); foreach (ParameterRename rename2 in renames) { if (string.Equals(rename2.InAssembly, item, StringComparison.OrdinalIgnoreCase)) { list2.Add(rename2); } } List list3 = new List(); foreach (MemberForward member2 in members) { if (string.Equals(member2.InAssembly, item, StringComparison.OrdinalIgnoreCase)) { list3.Add(member2); } } string text = Path.Combine(interopDirectory, item + ".dll"); if (!File.Exists(text)) { RefuseAll(result, list, list3, item, "not installed"); continue; } if (!originals.MayWrite(item)) { RefuseAll(result, list, list3, item, originals.RefusalFor(item)); continue; } try { ApplyTo(text, list, list3, list2, originals, result, log); } catch (Exception ex) { RefuseAll(result, list, list3, item, ex.Message); log.Error($"[inject] {item} was left untouched: {ex}"); } } return result; } private static void RefuseAll(Result result, List types, List members, string assembly, string why) { result.Refused.Add(assembly + ": " + why); foreach (TypeForward type in types) { result.Record(type.Key, "refused", why); } foreach (MemberForward member in members) { result.Record(member.Key, "refused", why); } } private static void ApplyTo(string livePath, List forwards, List members, List renames, InteropOriginals originals, Result result, ILog log) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Expected O, but got Unknown string directoryName = Path.GetDirectoryName(livePath); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(livePath); string text = livePath + ".polyfill-orig"; string sourceFileName = originals.SourceFor(fileNameWithoutExtension); if (!File.Exists(text)) { try { File.Copy(sourceFileName, text); } catch (Exception ex) { RefuseAll(result, forwards, members, fileNameWithoutExtension, "the untouched copy could not be made (" + ex.Message + ")"); return; } } string path = text; string text2 = Provenance.Sha256(text); string text3 = livePath + ".polyfill-tmp"; int num = 0; ShadowTypes.Begin(); List list = new List(); List list2 = new List(); try { DefaultAssemblyResolver val = new DefaultAssemblyResolver(); try { ModuleDefinition val2 = ReadWithResolver(path, directoryName, val); try { foreach (TypeForward forward in forwards) { if (val2.GetType(Full(forward)) != null) { Refuse(result, forward, "the name is taken here"); continue; } bool flag = !string.Equals(forward.TargetFullName, Full(forward), StringComparison.Ordinal); if (flag && forward.ByNativeClass) { if (FacadeTypes.TryAdd(val2, forward.Namespace, forward.Name, forward.TargetFullName, forward.Answers, out var refusal) == null) { Refuse(result, forward, "it cannot inherit from what it became, and " + refusal); continue; } result.Applied.Add(forward.InAssembly + "!" + Full(forward) + " -> a class around " + forward.TargetFullName + "'s native class"); result.Record(forward.Key, "applied", "a class around " + forward.TargetFullName + "'s native class"); list.Add(forward); num++; continue; } if (flag) { string refusal2; TypeDefinition val3 = ShadowTypes.TryAdd(val2, forward.Namespace, forward.Name, forward.TargetFullName, out refusal2, forward.TargetAssembly, forward.NestedIn); if (val3 == null) { Refuse(result, forward, "its name changed, and " + refusal2); continue; } string value; string text4 = (ShadowTypes.WithoutAClass.TryGetValue(((forward.Namespace.Length == 0) ? "" : (forward.Namespace + ".")) + forward.Name, out value) ? value : null); string text5 = (val3.IsEnum ? ("a copy of " + forward.TargetFullName + "'s members") : ("a class deriving from " + forward.TargetFullName)) + ((text4 == null) ? "" : (", but without its native class: " + text4)); result.Applied.Add($"{forward.InAssembly}!{Full(forward)} -> {text5}"); result.Record(forward.Key, "applied", text5); list.Add(forward); num++; continue; } AssemblyNameReference val4 = ScopeFor(val2, forward.TargetAssembly); if (val4 == null) { Refuse(result, forward, forward.TargetAssembly + " is not installed"); continue; } if (ShadowTypes.Resolve(val2, Full(forward), forward.TargetAssembly) == null) { Refuse(result, forward, forward.TargetAssembly + " has no " + Full(forward) + " to point at"); continue; } val2.ExportedTypes.Add(new ExportedType(forward.Namespace, forward.Name, val2, (IMetadataScope)(object)val4) { Attributes = (TypeAttributes)2097152 }); result.Applied.Add($"{forward.InAssembly}!{Full(forward)} -> {forward.TargetAssembly}"); result.Record(forward.Key, "applied", "pointed at " + forward.TargetAssembly); list.Add(forward); num++; } foreach (MemberForward member in members) { if (AddMemberForward(val2, member, result)) { list2.Add(member); num++; } } foreach (ParameterRename rename in renames) { if (PutParameterNameBack(val2, rename, result)) { num++; } } if (num == 0) { return; } Provenance.Add(val2, new Provenance.Mark { Source = text2, By = "0.11.16", Generator = originals.Generator.Digest(), At = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ") }); val2.Write(text3); } finally { ((IDisposable)val2)?.Dispose(); } } finally { ((IDisposable)val)?.Dispose(); } string text6 = Verify(text3, list, list2); if (text6 != null) { RefuseAll(result, list, list2, Path.GetFileName(livePath), "the written image is missing " + text6 + ", so the original was kept"); log.Error($"[inject] {Path.GetFileName(livePath)}: the written image does not contain {text6}. Nothing was replaced."); } else { File.Copy(text3, livePath, overwrite: true); result.Written++; result.Stamped.Add(new StampFile.Entry { Assembly = fileNameWithoutExtension, OriginalSha = text2, Repairs = num }); log.Msg($"[inject] {Path.GetFileName(livePath)}: {num} repair(s) added."); } } finally { try { if (File.Exists(text3)) { File.Delete(text3); } } catch { } } } private static bool PutParameterNameBack(ModuleDefinition module, ParameterRename rename, Result result) { //IL_0083: 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) string text = $"{rename.DeclaringType}::{rename.Method}({rename.Name})"; TypeDefinition type = module.GetType(rename.DeclaringType); if (type == null) { Refuse(result, rename, text, "the type it is on is not in this assembly"); return false; } MethodDefinition val = null; Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (!(((MemberReference)current).Name != rename.Method) && ((MethodReference)current).Parameters.Count == rename.ParameterCount) { if (val != null) { Refuse(result, rename, text, "more than one method here has that shape"); return false; } val = current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val == null) { Refuse(result, rename, text, "no method here has that shape"); return false; } if (rename.Index < 0 || rename.Index >= ((MethodReference)val).Parameters.Count) { Refuse(result, rename, text, "the parameter is not where the rule says"); return false; } ParameterDefinition val2 = ((MethodReference)val).Parameters[rename.Index]; if (((ParameterReference)val2).Name == rename.Name) { Refuse(result, rename, text, "it is already called that here"); return false; } if (((ParameterReference)val2).Name != rename.WasCalled) { Refuse(result, rename, text, $"this build calls it {((ParameterReference)val2).Name}, not {rename.WasCalled}, so the rule does " + "not describe this game"); return false; } ((ParameterReference)val2).Name = rename.Name; result.Applied.Add($"{rename.InAssembly}!{text} [was {rename.WasCalled}: {rename.Because}]"); result.Record(rename.Key, "applied", $"renamed from {rename.WasCalled} ({rename.Because})"); return true; } private static void Refuse(Result result, ParameterRename rename, string label, string why) { result.Refused.Add(label + ": " + why); result.Record(rename.Key, "refused", why); } private static bool AddMemberForward(ModuleDefinition module, MemberForward member, Result result) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Expected O, but got Unknown //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_043a: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Expected O, but got Unknown //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04ff: Unknown result type (might be due to invalid IL or missing references) string text = member.DeclaringType + "::" + member.OldName; TypeDefinition type = module.GetType(member.DeclaringType); if (type == null) { Refuse(result, member, text, "the type it was on is not in this assembly"); return false; } Bridge bridge = ((member.NewName == null) ? Registry.Find(member.InAssembly, member.DeclaringType, member.OldName, member.ParameterCount, member.ParameterTypes) : null); Enumerator enumerator; if ((bridge == null) ? (!member.SameNameNewReturn) : (!bridge.AllowOverload)) { enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { if (((MemberReference)enumerator.Current).Name == member.OldName) { Refuse(result, member, text, "the name is already taken here"); return false; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } if (member.NewName == null) { if (bridge == null) { Refuse(result, member, text, "nothing here knows what it became"); return false; } MethodDefinition val; try { val = bridge.Emit(module, type); } catch (Exception ex) { Refuse(result, member, text, "the rule for it failed on this build: " + ex.Message); MelonLogger.Warning("[inject] " + text + " emitter threw:\n" + ex); return false; } if (val == null) { Refuse(result, member, text, "the rule for it needs members this build does not have"); return false; } enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name == ((MemberReference)val).Name && SameShape(current, val)) { Refuse(result, member, text, "that exact signature is already here"); return false; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } type.Methods.Add(val); string text2 = (bridge.Verified(GameVersionSource.Current) ? bridge.Because : (bridge.Because + " (not verified on this build)")); result.Applied.Add($"{member.InAssembly}!{text} [rule: {text2}]"); result.Record(member.Key, "applied", text2); return true; } MethodDefinition val2 = null; enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current2 = enumerator.Current; if (!(((MemberReference)current2).Name != member.NewName)) { if (val2 != null) { Refuse(result, member, text, member.NewName + " is overloaded here, so which one it became is not decidable"); return false; } val2 = current2; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (val2 == null) { Refuse(result, member, text, member.NewName + " is not on this type after all"); return false; } if (((MethodReference)val2).HasGenericParameters) { Refuse(result, member, text, member.NewName + " is generic"); return false; } TypeDefinition val3 = ShadowTypes.Shadowing(module, ((MethodReference)val2).ReturnType); TypeReference val4 = (TypeReference)(((object)val3) ?? ((object)((MethodReference)val2).ReturnType)); if (member.SameNameNewReturn && val3 == null) { Refuse(result, member, text, "nothing stands in for what it hands back, so putting the name back a second time would only duplicate it"); return false; } if (ShadowTypes.BuriesAShadow(((MethodReference)val2).ReturnType)) { Refuse(result, member, text, "it hands back a renamed type wrapped in a list or an array, which cannot stand in for the old one"); return false; } MethodDefinition val5 = new MethodDefinition(member.OldName, (MethodAttributes)(0x86 | (val2.IsStatic ? 16 : 0)), val4); Enumerator enumerator2 = ((MethodReference)val2).Parameters.GetEnumerator(); try { while (enumerator2.MoveNext()) { ParameterDefinition current3 = enumerator2.Current; if (ShadowTypes.BuriesAShadow(((ParameterReference)current3).ParameterType)) { Refuse(result, member, text, "it takes a renamed type wrapped in " + ((MemberReference)((ParameterReference)current3).ParameterType).Name + ", which cannot stand in for the old one"); return false; } TypeDefinition val6 = ShadowTypes.Shadowing(module, ((ParameterReference)current3).ParameterType); if (val6 != null && ((ParameterReference)current3).ParameterType.IsByReference) { Refuse(result, member, text, "it takes " + ((MemberReference)((ParameterReference)current3).ParameterType).Name + " by reference, and a renamed type cannot be passed by reference under both names"); return false; } ((MethodReference)val5).Parameters.Add(new ParameterDefinition(((ParameterReference)current3).Name, current3.Attributes, (TypeReference)(((object)val6) ?? ((object)((ParameterReference)current3).ParameterType)))); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } ILProcessor iLProcessor = val5.Body.GetILProcessor(); if (!val2.IsStatic) { iLProcessor.Emit(OpCodes.Ldarg_0); } for (int i = 0; i < ((MethodReference)val2).Parameters.Count; i++) { iLProcessor.Emit(OpCodes.Ldarg, ((MethodReference)val5).Parameters[i]); } iLProcessor.Emit(OpCodes.Call, (MethodReference)(object)val2); if (val3 != null && !ShadowTypes.EmitRewrap(module, iLProcessor, val3, out var refusal)) { Refuse(result, member, text, "its answer cannot be handed back under the old name: " + refusal); return false; } iLProcessor.Emit(OpCodes.Ret); type.Methods.Add(val5); result.Applied.Add($"{member.InAssembly}!{text}() -> {member.NewName}() [{member.Rule}]"); result.Record(member.Key, "applied", member.NewName + " [" + member.Rule + "]"); return true; } private static void Refuse(Result result, MemberForward member, string label, string why) { result.Refused.Add(label + ": " + why); result.Record(member.Key, "refused", why); } private static void Refuse(Result result, TypeForward forward, string why) { result.Refused.Add(Full(forward) + ": " + why); result.Record(forward.Key, "refused", why); } private static string Verify(string writtenPath, List forwards, List members) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) ModuleDefinition val = ModuleDefinition.ReadModule(writtenPath, new ReaderParameters { InMemory = true }); try { foreach (TypeForward forward in forwards) { bool flag = val.GetType(Full(forward)) != null; if (!flag) { Enumerator enumerator2 = val.ExportedTypes.GetEnumerator(); try { while (enumerator2.MoveNext()) { ExportedType current2 = enumerator2.Current; if (current2.Namespace == forward.Namespace && current2.Name == forward.Name) { flag = true; break; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } if (!flag) { return Full(forward); } } foreach (MemberForward member in members) { TypeDefinition type = val.GetType(member.DeclaringType); bool flag2 = false; if (type != null) { Enumerator enumerator4 = type.Methods.GetEnumerator(); try { while (enumerator4.MoveNext()) { MethodDefinition current4 = enumerator4.Current; if (((MemberReference)current4).Name == member.OldName && ((MethodReference)current4).Parameters.Count == member.ParameterCount) { flag2 = true; break; } } } finally { ((IDisposable)enumerator4/*cast due to .constrained prefix*/).Dispose(); } } if (!flag2) { return member.DeclaringType + "::" + member.OldName; } } if (Provenance.Read(val) == null) { return "Provenance"; } return null; } finally { ((IDisposable)val)?.Dispose(); } } private static bool SameShape(MethodDefinition a, MethodDefinition b) { if (((MethodReference)a).Parameters.Count != ((MethodReference)b).Parameters.Count) { return false; } for (int i = 0; i < ((MethodReference)a).Parameters.Count; i++) { if (((MemberReference)((ParameterReference)((MethodReference)a).Parameters[i]).ParameterType).FullName != ((MemberReference)((ParameterReference)((MethodReference)b).Parameters[i]).ParameterType).FullName) { return false; } } return true; } private static ModuleDefinition ReadWithResolver(string path, string interop, DefaultAssemblyResolver resolver) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown ((BaseAssemblyResolver)resolver).AddSearchDirectory(interop); try { string directoryName = Path.GetDirectoryName(typeof(object).Assembly.Location); if (!string.IsNullOrEmpty(directoryName)) { ((BaseAssemblyResolver)resolver).AddSearchDirectory(directoryName); } } catch { } try { string directoryName2 = Path.GetDirectoryName(typeof(MelonPlugin).Assembly.Location); if (!string.IsNullOrEmpty(directoryName2)) { ((BaseAssemblyResolver)resolver).AddSearchDirectory(directoryName2); } } catch { } return ModuleDefinition.ReadModule(path, new ReaderParameters { InMemory = true, AssemblyResolver = (IAssemblyResolver)(object)resolver }); } private static string Full(TypeForward forward) { if (forward.NestedIn == null) { if (!string.IsNullOrEmpty(forward.Namespace)) { return forward.Namespace + "." + forward.Name; } return forward.Name; } return forward.NestedIn + "/" + forward.Name; } private static AssemblyNameReference ScopeFor(ModuleDefinition module, string assemblyName) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown Enumerator enumerator = module.AssemblyReferences.GetEnumerator(); try { while (enumerator.MoveNext()) { AssemblyNameReference current = enumerator.Current; if (string.Equals(current.Name, assemblyName, StringComparison.OrdinalIgnoreCase)) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } AssemblyNameReference val = new AssemblyNameReference(assemblyName, new Version(0, 0, 0, 0)); module.AssemblyReferences.Add(val); return val; } internal static string PendingMarker(string userDataDirectory) { return PolyfillPaths.RestorePending(userDataDirectory); } internal static int Restore(string interopDirectory, ILog log) { int num = 0; string[] files = Directory.GetFiles(interopDirectory, "*.polyfill-orig"); foreach (string text in files) { string text2 = text.Substring(0, text.Length - ".polyfill-orig".Length); try { File.Copy(text, text2, overwrite: true); File.Delete(text); num++; } catch (Exception ex) { log.Error("[inject] could not restore " + Path.GetFileName(text2) + ": " + ex.Message); } } return num; } } internal sealed class InteropIndex : IDisposable { private sealed class PinnedResolver : DefaultAssemblyResolver { internal void Pin(AssemblyDefinition assembly) { ((DefaultAssemblyResolver)this).RegisterAssembly(assembly); } } private readonly Dictionary _pathByAssembly = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _modules = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly PinnedResolver _resolver = new PinnedResolver(); private readonly HashSet _game = new HashSet(StringComparer.OrdinalIgnoreCase); private Dictionary> _bySimpleName; internal string Directory { get; } internal IAssemblyResolver Resolver => (IAssemblyResolver)(object)_resolver; internal int AssemblyCount => _pathByAssembly.Count; internal InteropIndex(string interopDirectory, InteropOriginals originals, IEnumerable libraryDirectories, IEnumerable searchOnlyDirectories) { Directory = interopDirectory; if (!string.IsNullOrEmpty(interopDirectory) && System.IO.Directory.Exists(interopDirectory)) { ((BaseAssemblyResolver)_resolver).AddSearchDirectory(interopDirectory); string[] files = System.IO.Directory.GetFiles(interopDirectory, "*.dll"); foreach (string text in files) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); _pathByAssembly[fileNameWithoutExtension] = originals?.SourceFor(fileNameWithoutExtension) ?? text; _game.Add(fileNameWithoutExtension); } } foreach (string libraryDirectory in libraryDirectories) { if (string.IsNullOrEmpty(libraryDirectory) || !System.IO.Directory.Exists(libraryDirectory)) { continue; } ((BaseAssemblyResolver)_resolver).AddSearchDirectory(libraryDirectory); string[] files = System.IO.Directory.GetFiles(libraryDirectory, "*.dll"); foreach (string text2 in files) { string text3; try { text3 = AssemblyName.GetAssemblyName(text2)?.Name; } catch { continue; } if (!string.IsNullOrEmpty(text3) && !_pathByAssembly.ContainsKey(text3)) { _pathByAssembly[text3] = text2; } } } foreach (string searchOnlyDirectory in searchOnlyDirectories) { if (!string.IsNullOrEmpty(searchOnlyDirectory) && System.IO.Directory.Exists(searchOnlyDirectory)) { ((BaseAssemblyResolver)_resolver).AddSearchDirectory(searchOnlyDirectory); } } try { string directoryName = Path.GetDirectoryName(typeof(object).Assembly.Location); if (!string.IsNullOrEmpty(directoryName)) { ((BaseAssemblyResolver)_resolver).AddSearchDirectory(directoryName); } } catch { } } internal static string LocateDirectory() { try { if (typeof(MelonEnvironment).GetProperty("Il2CppAssembliesDirectory", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) is string { Length: >0 } text && System.IO.Directory.Exists(text)) { return text; } } catch { } try { string melonLoaderDirectory = MelonEnvironment.MelonLoaderDirectory; if (!string.IsNullOrEmpty(melonLoaderDirectory)) { string text2 = Path.Combine(melonLoaderDirectory, "Il2CppAssemblies"); if (System.IO.Directory.Exists(text2)) { return text2; } } } catch { } return null; } internal bool IsTracked(string assemblyName) { if (assemblyName != null) { return _pathByAssembly.ContainsKey(assemblyName); } return false; } internal string Kind(string assemblyName) { if (assemblyName == null || !_game.Contains(assemblyName)) { return "library"; } return "game"; } internal ModuleDefinition Module(string assemblyName) { //IL_002c: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if (assemblyName == null) { return null; } if (_modules.TryGetValue(assemblyName, out var value)) { return value; } if (!_pathByAssembly.TryGetValue(assemblyName, out var value2)) { return null; } ModuleDefinition val = null; try { val = ModuleDefinition.ReadModule(value2, new ReaderParameters { InMemory = true, ReadingMode = (ReadingMode)2, AssemblyResolver = (IAssemblyResolver)(object)_resolver }); if (val.Assembly != null) { _resolver.Pin(val.Assembly); } } catch { } _modules[assemblyName] = val; return val; } internal TypeDefinition FindType(string assemblyName, string fullName) { ModuleDefinition val = Module(assemblyName); if (val == null || fullName == null) { return null; } return val.GetType(fullName) ?? val.GetType(fullName.Replace('+', '/')); } internal IReadOnlyList BySimpleName(string simpleName) { if (_bySimpleName == null) { _bySimpleName = BuildSimpleNameIndex(); } if (!_bySimpleName.TryGetValue(simpleName, out var value)) { return Array.Empty(); } return value; } internal IEnumerable SimpleNames() { if (_bySimpleName == null) { _bySimpleName = BuildSimpleNameIndex(); } return _bySimpleName.Keys; } private Dictionary> BuildSimpleNameIndex() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) Dictionary> dictionary = new Dictionary>(StringComparer.Ordinal); foreach (string item in _game) { ModuleDefinition val = Module(item); if (val == null) { continue; } try { Enumerator enumerator2 = val.Types.GetEnumerator(); try { while (enumerator2.MoveNext()) { TypeDefinition current2 = enumerator2.Current; Add(dictionary, current2); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } catch { } } return dictionary; } private static void Add(Dictionary> index, TypeDefinition type) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!index.TryGetValue(((MemberReference)type).Name, out var value)) { value = (index[((MemberReference)type).Name] = new List()); } value.Add(type); if (!type.HasNestedTypes) { return; } Enumerator enumerator = type.NestedTypes.GetEnumerator(); try { while (enumerator.MoveNext()) { TypeDefinition current = enumerator.Current; Add(index, current); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } public void Dispose() { foreach (ModuleDefinition value in _modules.Values) { try { if (value != null) { value.Dispose(); } } catch { } } _modules.Clear(); try { ((BaseAssemblyResolver)_resolver).Dispose(); } catch { } } } internal sealed class InteropOriginals { internal enum Origin { Seed, Reuse, Reseed, StandDown, Regenerated } private readonly Dictionary _origin = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _source = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly string _directory; private DateTime? _generationTime; private bool _generationTimeAsked; private int _adopted; internal GeneratorIdentity Generator { get; private set; } internal string StoodDownBecause { get; private set; } private InteropOriginals(string directory) { _directory = directory; } internal static InteropOriginals Take(string directory, bool mayAct, ILog log) { InteropOriginals interopOriginals = new InteropOriginals(directory) { Generator = GeneratorIdentity.Read() }; StampFile.Stamp stamp = StampFile.Read(); if (!interopOriginals.Generator.IsKnown) { log.Msg("[stamp] MelonLoader's generator config could not be read, so a generation that did not finish cannot be told apart from one that did. Everything else still holds."); } foreach (string item in interopOriginals.Examine(stamp)) { interopOriginals.DecideOne(item, stamp, mayAct, log); } interopOriginals.Summarise(stamp, mayAct, log); return interopOriginals; } internal string SourceFor(string assembly) { if (assembly != null && _source.TryGetValue(assembly, out var value)) { return value; } return Live(assembly); } internal Origin OriginOf(string assembly) { if (assembly == null || !_origin.TryGetValue(assembly, out var value)) { return Origin.Seed; } return value; } internal bool MayWrite(string assembly) { if (StoodDownBecause != null) { return false; } Origin origin = OriginOf(assembly); if (origin != Origin.StandDown) { return origin != Origin.Regenerated; } return false; } internal string RefusalFor(string assembly) { if (StoodDownBecause != null) { return StoodDownBecause; } return OriginOf(assembly) switch { Origin.StandDown => "no untouched copy of this assembly could be established", Origin.Regenerated => "the generated assemblies were put back this launch", _ => null, }; } private IEnumerable Examine(StampFile.Stamp stamp) { SortedSet sortedSet = new SortedSet(StringComparer.OrdinalIgnoreCase); try { string[] files = Directory.GetFiles(_directory, "*.polyfill-orig"); foreach (string text in files) { string path = text.Substring(0, text.Length - ".polyfill-orig".Length); sortedSet.Add(Path.GetFileNameWithoutExtension(path)); } } catch { } foreach (StampFile.Entry assembly in stamp.Assemblies) { if (!string.IsNullOrEmpty(assembly.Assembly)) { sortedSet.Add(assembly.Assembly); } } return sortedSet; } private void DecideOne(string assembly, StampFile.Stamp stamp, bool mayAct, ILog log) { string text = Live(assembly); string text2 = text + ".polyfill-orig"; bool num = File.Exists(text); bool flag = File.Exists(text2); if (!num) { Set(assembly, Origin.StandDown, text); if (flag) { log.Msg("[stamp] " + assembly + " is no longer installed; the copy kept of it was left alone."); } return; } Provenance.Mark mark = Provenance.ReadFrom(text); if (mark == null) { if (!flag) { Set(assembly, Origin.Seed, text); return; } if (WrittenAfterGeneration(text)) { Set(assembly, Origin.Reuse, text2); _adopted++; log.Msg("[stamp] " + assembly + " was repaired by an older Polyfill, from before it left a note in what it writes. The copy kept beside it is still the original and is used as one; from now on the note settles this without a timestamp."); return; } Set(assembly, Origin.Reseed, text); if (mayAct) { try { File.Delete(text2); } catch (Exception ex) { log.Warning("[stamp] the stale copy of " + assembly + " could not be removed: " + ex.Message); } } } else if (!flag) { Set(assembly, Origin.StandDown, text); log.Warning("[stamp] " + assembly + " was repaired by Polyfill and the untouched copy beside it is gone, so nothing can be rebuilt from it. Left exactly as it is. `polyfillregen` makes MelonLoader generate it again."); } else if (Generator.IsKnown && mark.Generator != Generator.Digest()) { Set(assembly, Origin.Regenerated, text2); StoodDownBecause = "the interop assemblies were put back because a regeneration did not finish"; if (mayAct) { try { File.Copy(text2, text, overwrite: true); File.Delete(text2); } catch (Exception ex2) { log.Error("[stamp] " + assembly + " could not be put back: " + ex2.Message); } } log.Warning("[stamp] " + assembly + " is Polyfill's output, but MelonLoader's generator has changed its inputs since - so the rebuild did not finish. The untouched copy was put back and nothing was repaired this launch. If this repeats, delete MelonLoader/Dependencies/Il2CppAssemblyGenerator/Cpp2IL/cpp2il_out and start again."); } else { string text3 = Provenance.Sha256(text2); if (text3 == null || !string.Equals(text3, mark.Source, StringComparison.OrdinalIgnoreCase)) { Set(assembly, Origin.StandDown, text); log.Warning("[stamp] the copy kept of " + assembly + " is not the one it was built from, so which of the two is the original cannot be settled here. Both were left alone."); } else { Set(assembly, Origin.Reuse, text2); } } } private void Summarise(StampFile.Stamp stamp, bool mayAct, ILog log) { int num = 0; int num2 = 0; int num3 = 0; using (Dictionary.ValueCollection.Enumerator enumerator = _origin.Values.GetEnumerator()) { while (enumerator.MoveNext()) { switch (enumerator.Current) { case Origin.Reseed: num++; break; case Origin.Reuse: num2++; break; case Origin.StandDown: num3++; break; } } } if (num > 0) { string text = Report.GameVersion(); string value = ((string.IsNullOrEmpty(stamp.Game) || stamp.Game == text) ? "" : $"Schedule I {stamp.Game} -> Schedule I {text}. "); log.Msg($"[stamp] {value}MelonLoader generated the interop assemblies again, so the {num} " + "copy/copies Polyfill kept of the old ones are " + (mayAct ? "stale and were removed. " : "stale and were left in place (DryRun). ") + "Starting from the new originals."); StampFile.Clear(); } else if (num2 - _adopted > 0) { log.Msg($"[stamp] {num2 - _adopted} assembly/assemblies still match what Polyfill built " + "them from."); } if (num3 > 0) { log.Warning($"[stamp] {num3} assembly/assemblies were left untouched because no original " + "could be established for them."); } } private bool WrittenAfterGeneration(string live) { DateTime? dateTime = GenerationTime(); if (!dateTime.HasValue) { return false; } try { return File.GetLastWriteTimeUtc(live) > dateTime.Value.AddSeconds(60.0); } catch { return false; } } private DateTime? GenerationTime() { if (_generationTime.HasValue) { return _generationTime; } if (_generationTimeAsked) { return null; } _generationTimeAsked = true; try { DateTime dateTime = DateTime.MinValue; string[] files = Directory.GetFiles(_directory, "*.dll"); foreach (string text in files) { if (!File.Exists(text + ".polyfill-orig")) { DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(text); if (lastWriteTimeUtc > dateTime) { dateTime = lastWriteTimeUtc; } } } if (dateTime != DateTime.MinValue) { _generationTime = dateTime; } } catch { } return _generationTime; } private void Set(string assembly, Origin origin, string source) { _origin[assembly] = origin; _source[assembly] = source; } private string Live(string assembly) { if (assembly != null) { return Path.Combine(_directory, assembly + ".dll"); } return null; } } internal sealed class Candidate { internal string Rule; internal string NewName; internal IMemberDefinition Member; internal bool KindChanged; internal Candidate(string rule, IMemberDefinition member, bool kindChanged = false) { Rule = rule; Member = member; NewName = member.Name; KindChanged = kindChanged; } } internal static class NameHeuristics { private static readonly Regex RpcHash = new Regex("^(?Rpc(?:Logic|Writer|Reader)___)(?.+)_(?\\d+)$", RegexOptions.Compiled); internal static List ForMethod(TypeDefinition type, string wanted, MethodReference signature) { //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (type == null) { return list; } Match match = RpcHash.Match(wanted); Enumerator enumerator; if (match.Success) { string value = match.Groups["prefix"].Value; string value2 = match.Groups["base"].Value; enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; Match match2 = RpcHash.Match(((MemberReference)current).Name); if (match2.Success && !(match2.Groups["prefix"].Value != value) && !(match2.Groups["base"].Value != value2) && (signature == null || SameParameters(signature, current))) { list.Add(new Candidate("rpc-hash", (IMemberDefinition)(object)current)); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (list.Count > 0) { return list; } } enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current2 = enumerator.Current; if (!(((MemberReference)current2).Name == wanted) && IsNameVariant(wanted, ((MemberReference)current2).Name, out var rule) && (signature == null || SameParameters(signature, current2))) { list.Add(new Candidate(rule, (IMemberDefinition)(object)current2)); } } return list; } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } internal static List ForField(TypeDefinition type, string wanted) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (type == null) { return list; } Enumerator enumerator = type.Fields.GetEnumerator(); try { while (enumerator.MoveNext()) { FieldDefinition current = enumerator.Current; if (!(((MemberReference)current).Name == wanted) && IsNameVariant(wanted, ((MemberReference)current).Name, out var rule)) { list.Add(new Candidate(rule, (IMemberDefinition)(object)current)); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } Enumerator enumerator2 = type.Properties.GetEnumerator(); try { while (enumerator2.MoveNext()) { PropertyDefinition current2 = enumerator2.Current; string rule2; if (((MemberReference)current2).Name == wanted) { list.Add(new Candidate("field-to-property", (IMemberDefinition)(object)current2, kindChanged: true)); } else if (IsNameVariant(wanted, ((MemberReference)current2).Name, out rule2)) { list.Add(new Candidate(rule2 + "+field-to-property", (IMemberDefinition)(object)current2, kindChanged: true)); } } return list; } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } internal static bool IsNameVariant(string wanted, string have, out string rule) { rule = null; if (wanted == null || have == null || wanted == have) { return false; } if (string.Equals(wanted, have, StringComparison.OrdinalIgnoreCase)) { rule = "casing"; return true; } if (Trim(wanted, '_') == Trim(have, '_') && Trim(wanted, '_').Length > 0) { rule = "underscore"; return true; } if (BackingFieldOf(have) == wanted || BackingFieldOf(wanted) == have) { rule = "backing-field"; return true; } if (StripWeaverUnderscores(wanted) == StripWeaverUnderscores(have)) { rule = "syncvar-accessor"; return true; } if (string.Equals(Normalize(wanted), Normalize(have), StringComparison.OrdinalIgnoreCase) && Normalize(wanted).Length > 0) { rule = "underscore+casing"; return true; } return false; } private static string Trim(string s, char c) { return s.Trim(c); } private static string Normalize(string name) { return Trim(StripWeaverUnderscores(name), '_'); } private static string BackingFieldOf(string name) { if (name == null || !name.StartsWith("<", StringComparison.Ordinal)) { return null; } int num = name.IndexOf(">k__BackingField", StringComparison.Ordinal); if (num <= 1) { return null; } return name.Substring(1, num - 1); } private static string StripWeaverUnderscores(string name) { if (name == null) { return null; } StringBuilder stringBuilder = new StringBuilder(name.Length); bool flag = false; foreach (char c in name) { if (c == '_') { if (!flag) { stringBuilder.Append(c); } flag = true; } else { stringBuilder.Append(c); flag = false; } } return stringBuilder.ToString(); } internal static bool SameParameters(MethodReference wanted, MethodDefinition have) { if (wanted == null || have == null) { return false; } int num = wanted.Parameters?.Count ?? 0; if (num != (((MethodReference)have).Parameters?.Count ?? 0)) { return false; } if (wanted.GenericParameters.Count != ((MethodReference)have).GenericParameters.Count) { return false; } for (int i = 0; i < num; i++) { if (!SameType(((ParameterReference)wanted.Parameters[i]).ParameterType, ((ParameterReference)((MethodReference)have).Parameters[i]).ParameterType)) { return false; } } return true; } private static bool SameType(TypeReference a, TypeReference b) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (a == b) { return true; } if (a == null || b == null) { return false; } IModifierType val = (IModifierType)(object)((a is IModifierType) ? a : null); if (val != null) { return SameType(val.ElementType, b); } IModifierType val2 = (IModifierType)(object)((b is IModifierType) ? b : null); if (val2 != null) { return SameType(a, val2.ElementType); } GenericParameter val3 = (GenericParameter)(object)((a is GenericParameter) ? a : null); if (val3 != null) { GenericParameter val4 = (GenericParameter)(object)((b is GenericParameter) ? b : null); if (val4 != null && val3.Position == val4.Position) { return val3.Type == val4.Type; } return false; } if (b is GenericParameter) { return false; } ArrayType val5 = (ArrayType)(object)((a is ArrayType) ? a : null); if (val5 != null) { ArrayType val6 = (ArrayType)(object)((b is ArrayType) ? b : null); if (val6 != null && val5.Rank == val6.Rank) { return SameType(((TypeSpecification)val5).ElementType, ((TypeSpecification)val6).ElementType); } return false; } ByReferenceType val7 = (ByReferenceType)(object)((a is ByReferenceType) ? a : null); if (val7 != null) { ByReferenceType val8 = (ByReferenceType)(object)((b is ByReferenceType) ? b : null); if (val8 != null) { return SameType(((TypeSpecification)val7).ElementType, ((TypeSpecification)val8).ElementType); } return false; } PointerType val9 = (PointerType)(object)((a is PointerType) ? a : null); if (val9 != null) { PointerType val10 = (PointerType)(object)((b is PointerType) ? b : null); if (val10 != null) { return SameType(((TypeSpecification)val9).ElementType, ((TypeSpecification)val10).ElementType); } return false; } GenericInstanceType val11 = (GenericInstanceType)(object)((a is GenericInstanceType) ? a : null); if (val11 != null) { GenericInstanceType val12 = (GenericInstanceType)(object)((b is GenericInstanceType) ? b : null); if (val12 == null) { return false; } if (!SameType(((TypeSpecification)val11).ElementType, ((TypeSpecification)val12).ElementType)) { return false; } if (val11.GenericArguments.Count != val12.GenericArguments.Count) { return false; } for (int i = 0; i < val11.GenericArguments.Count; i++) { if (!SameType(val11.GenericArguments[i], val12.GenericArguments[i])) { return false; } } return true; } if (b is GenericInstanceType) { return false; } return ((MemberReference)a).FullName == ((MemberReference)b).FullName; } } internal static class Provenance { internal sealed class Mark { internal string Source; internal string By; internal string Generator; internal string At; } internal const string MarkerType = "Provenance"; internal static void Add(ModuleDefinition module, Mark mark) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown if (module.GetType("Provenance") == null) { TypeDefinition val = new TypeDefinition("", "Provenance", (TypeAttributes)1048960, module.TypeSystem.Object); Constant(module, val, "Source", mark.Source); Constant(module, val, "By", mark.By); Constant(module, val, "Generator", mark.Generator); Constant(module, val, "At", mark.At); module.Types.Add(val); } } internal static Mark Read(ModuleDefinition module) { //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) TypeDefinition val = ((module != null) ? module.GetType("Provenance") : null); if (val == null) { return null; } Mark mark = new Mark(); Enumerator enumerator = val.Fields.GetEnumerator(); try { while (enumerator.MoveNext()) { FieldDefinition current = enumerator.Current; string text = current.Constant as string; switch (((MemberReference)current).Name) { case "Source": mark.Source = text; break; case "By": mark.By = text; break; case "Generator": mark.Generator = text; break; case "At": mark.At = text; break; } } return mark; } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } internal static Mark ReadFrom(string path) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown try { ModuleDefinition val = ModuleDefinition.ReadModule(path, new ReaderParameters { InMemory = true }); try { return Read(val); } finally { ((IDisposable)val)?.Dispose(); } } catch { return null; } } internal static string Sha256(string path) { try { using FileStream inputStream = File.OpenRead(path); using SHA256 sHA = SHA256.Create(); return Convert.ToHexString(sHA.ComputeHash(inputStream)); } catch { return null; } } private static void Constant(ModuleDefinition module, TypeDefinition type, string name, string value) { //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: Expected O, but got Unknown type.Fields.Add(new FieldDefinition(name, (FieldAttributes)32854, module.TypeSystem.String) { Constant = (value ?? "") }); } } internal static class Report { internal static string Directory => PolyfillPaths.Folder(MelonEnvironment.UserDataDirectory); internal static string LastRunPath => PolyfillPaths.LastRun(MelonEnvironment.UserDataDirectory); internal static string GameVersion() { return GameVersionSource.Raw; } internal static void Write(List reports, string interopDirectory, int assemblyCount, List dropped) { RunReport runReport = new RunReport { Generated = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"), Game = GameVersion(), Interop = (interopDirectory ?? "?"), AssemblyCount = assemblyCount }; runReport.Mods.AddRange(reports); if (dropped != null) { runReport.Dropped.AddRange(dropped); } try { System.IO.Directory.CreateDirectory(Directory); File.WriteAllText(LastRunPath, runReport.Text()); } catch (Exception ex) { Instance log = Plugin.Log; if (log != null) { log.Warning("[report] could not be written: " + ex.Message); } } } } internal static class ShadowTypes { private static readonly Dictionary Made = new Dictionary(StringComparer.Ordinal); internal static readonly Dictionary WithoutAClass = new Dictionary(StringComparer.Ordinal); internal static TypeDefinition TryAdd(ModuleDefinition module, string oldNamespace, string oldName, string targetFullName, out string refusal, string targetAssembly = null, string nestedIn = null) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) refusal = null; TypeDefinition val = Resolve(module, targetFullName, targetAssembly); if (val == null) { refusal = "the type it became is not where it was said to be"; return null; } if (val.IsEnum) { string refusal2; TypeDefinition val2 = Enum(module, oldNamespace, oldName, val, nestedIn, out refusal2); if (val2 == null) { refusal = refusal2; return null; } if (!Register(module, val2, nestedIn, out refusal)) { return null; } Made[((MemberReference)val).FullName] = val2; return val2; } if (val.IsInterface || ((TypeReference)val).IsValueType) { refusal = ((MemberReference)val).FullName + " is not a class"; return null; } if (val.IsSealed) { refusal = ((MemberReference)val).FullName + " is sealed, so nothing can stand in for it"; return null; } if (((TypeReference)val).HasGenericParameters) { refusal = ((MemberReference)val).FullName + " is generic"; return null; } MethodDefinition val3 = PointerConstructor(val); if (val3 == null) { refusal = ((MemberReference)val).FullName + " has no pointer constructor to build on"; return null; } TypeDefinition val4 = new TypeDefinition(oldNamespace, oldName, (TypeAttributes)1048577, module.ImportReference((TypeReference)(object)val)); MethodDefinition val5 = new MethodDefinition(".ctor", (MethodAttributes)6278, module.TypeSystem.Void); ((MethodReference)val5).Parameters.Add(new ParameterDefinition("pointer", (ParameterAttributes)0, module.TypeSystem.IntPtr)); ILProcessor iLProcessor = val5.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldarg_0); iLProcessor.Emit(OpCodes.Ldarg_1); iLProcessor.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val3)); iLProcessor.Emit(OpCodes.Ret); val4.Methods.Add(val5); MethodDefinition val6 = Parameterless(val); if (val6 != null) { MethodDefinition val7 = new MethodDefinition(".ctor", (MethodAttributes)6278, module.TypeSystem.Void); ILProcessor iLProcessor2 = val7.Body.GetILProcessor(); iLProcessor2.Emit(OpCodes.Ldarg_0); iLProcessor2.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val6)); iLProcessor2.Emit(OpCodes.Ret); val4.Methods.Add(val7); } if (nestedIn != null) { TypeDefinition type = module.GetType(nestedIn); if (type == null) { refusal = nestedIn + ", which it was nested in, is not in this assembly"; return null; } Enumerator enumerator = type.NestedTypes.GetEnumerator(); try { while (enumerator.MoveNext()) { if (((MemberReference)enumerator.Current).Name == oldName) { refusal = "the name is taken inside " + nestedIn; return null; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } ((TypeReference)val4).Namespace = ""; val4.Attributes = (TypeAttributes)1048578; type.NestedTypes.Add(val4); } else { module.Types.Add(val4); } CarryTheClassPointer(module, val4, val); Made[((MemberReference)val).FullName] = val4; return val4; } private static void CarryTheClassPointer(ModuleDefinition module, TypeDefinition shadow, TypeDefinition target) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_006a: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) string why; FieldReference val = ClassPointerField(target, out why); if (val == null) { WithoutAClass[((MemberReference)shadow).FullName] = why; return; } FieldReference val2 = module.ImportReference(new FieldReference(((MemberReference)val).Name, val.FieldType, (TypeReference)(object)Keyed(module, ((MemberReference)val).DeclaringType, (TypeReference)(object)shadow))); MethodDefinition val3 = new MethodDefinition(".cctor", (MethodAttributes)6289, module.TypeSystem.Void); ILProcessor iLProcessor = val3.Body.GetILProcessor(); iLProcessor.Emit(OpCodes.Ldsfld, module.ImportReference(val)); iLProcessor.Emit(OpCodes.Stsfld, val2); iLProcessor.Emit(OpCodes.Ret); shadow.Methods.Add(val3); shadow.Attributes = (TypeAttributes)(shadow.Attributes & -1048577); } private static FieldReference ClassPointerField(TypeDefinition target, out string why) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) why = null; MethodDefinition val = null; Enumerator enumerator = target.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (current.IsConstructor && current.IsStatic) { val = current; break; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (((val != null) ? val.Body : null) == null) { why = "it has no static constructor to read a native class out of"; return null; } FieldReference val2 = null; Enumerator enumerator2 = val.Body.Instructions.GetEnumerator(); try { while (enumerator2.MoveNext()) { Instruction current2 = enumerator2.Current; if (current2.OpCode != OpCodes.Stsfld) { continue; } object operand = current2.Operand; FieldReference val3 = (FieldReference)((operand is FieldReference) ? operand : null); if (val3 == null) { continue; } TypeReference declaringType = ((MemberReference)val3).DeclaringType; GenericInstanceType val4 = (GenericInstanceType)(object)((declaringType is GenericInstanceType) ? declaringType : null); if (val4 != null && val4.GenericArguments.Count == 1 && !(((MemberReference)val4.GenericArguments[0]).FullName != ((MemberReference)target).FullName) && !(((MemberReference)val3.FieldType).FullName != "System.IntPtr") && LooksLikeAStore(val4)) { if (val2 != null && ((MemberReference)val2).FullName != ((MemberReference)val3).FullName) { why = "it writes to more than one store this could be, and picking one would be a guess"; return null; } val2 = val3; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } if (val2 == null) { why = "it does not put its native class anywhere this can read"; } return val2; } private static bool LooksLikeAStore(GenericInstanceType keyed) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) TypeDefinition val; try { val = ((TypeSpecification)keyed).ElementType.Resolve(); } catch { return false; } if (val == null || !val.IsAbstract || !val.IsSealed) { return false; } if (((TypeReference)val).GenericParameters.Count != 1) { return false; } int num = 0; bool flag = false; Enumerator enumerator = val.Fields.GetEnumerator(); try { while (enumerator.MoveNext()) { FieldDefinition current = enumerator.Current; if (current.IsStatic && current.IsPublic) { if (((MemberReference)((FieldReference)current).FieldType).FullName == "System.IntPtr") { num++; } else if (((MemberReference)((FieldReference)current).FieldType).FullName == "System.Type") { flag = true; } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return num == 1 && flag; } private static GenericInstanceType Keyed(ModuleDefinition module, TypeReference store, TypeReference on) { //IL_0002: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown GenericInstanceType val = new GenericInstanceType(module.ImportReference(((TypeSpecification)(GenericInstanceType)store).ElementType)); val.GenericArguments.Add(on); return val; } internal static void Begin() { Made.Clear(); WithoutAClass.Clear(); } internal static TypeDefinition Shadowing(ModuleDefinition module, TypeReference type) { if (type == null || !Made.TryGetValue(((MemberReference)type).FullName, out var value)) { return null; } return value; } internal static bool BuriesAShadow(TypeReference type) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (type == null) { return false; } GenericInstanceType val = (GenericInstanceType)(object)((type is GenericInstanceType) ? type : null); if (val != null) { Enumerator enumerator = val.GenericArguments.GetEnumerator(); try { while (enumerator.MoveNext()) { TypeReference current = enumerator.Current; if (Made.ContainsKey(((MemberReference)current).FullName) || BuriesAShadow(current)) { return true; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return false; } TypeReference obj = ((type is ArrayType) ? type : null); object obj2 = ((obj != null) ? ((TypeSpecification)obj).ElementType : null); if (obj2 == null) { TypeReference obj3 = ((type is ByReferenceType) ? type : null); obj2 = ((obj3 != null) ? ((TypeSpecification)obj3).ElementType : null); } TypeReference val2 = (TypeReference)obj2; if (val2 == null) { return false; } if (!Made.ContainsKey(((MemberReference)val2).FullName)) { return BuriesAShadow(val2); } return true; } internal static bool EmitRewrap(ModuleDefinition module, ILProcessor il, TypeDefinition shadow, out string refusal) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) refusal = null; MethodDefinition val = PointerGetter(shadow); MethodDefinition val2 = PointerConstructor(shadow); if (val == null) { refusal = "Il2CppObjectBase.Pointer is not on it"; return false; } if (val2 == null) { refusal = "the shadow has no pointer constructor"; return false; } Instruction val3 = il.Create(OpCodes.Ret); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, val3); il.Emit(OpCodes.Call, module.ImportReference((MethodReference)(object)val)); il.Emit(OpCodes.Newobj, module.ImportReference((MethodReference)(object)val2)); il.Emit(OpCodes.Ret); il.Append(val3); return true; } private static bool Register(ModuleDefinition module, TypeDefinition type, string nestedIn, out string refusal) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) refusal = null; if (nestedIn == null) { module.Types.Add(type); return true; } TypeDefinition type2 = module.GetType(nestedIn); if (type2 == null) { refusal = nestedIn + ", which it was nested in, is not in this assembly"; return false; } Enumerator enumerator = type2.NestedTypes.GetEnumerator(); try { while (enumerator.MoveNext()) { if (string.Equals(((MemberReference)enumerator.Current).Name, ((MemberReference)type).Name, StringComparison.Ordinal)) { refusal = "the name is taken inside " + nestedIn; return false; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } type.Attributes = (TypeAttributes)((type.Attributes & -8) | 2); type2.NestedTypes.Add(type); return true; } private static TypeDefinition Enum(ModuleDefinition module, string oldNamespace, string oldName, TypeDefinition target, string nestedIn, out string refusal) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown refusal = null; FieldDefinition val = UnderlyingOf(target); if (val == null) { refusal = ((MemberReference)target).FullName + " is an enum with no value field to copy"; return null; } TypeReference val2 = module.ImportReference(target.BaseType); TypeDefinition val3 = new TypeDefinition((nestedIn == null) ? oldNamespace : "", oldName, (TypeAttributes)257, val2); FieldDefinition val4 = new FieldDefinition("value__", (FieldAttributes)1542, module.ImportReference(((FieldReference)val).FieldType)); val3.Fields.Add(val4); int num = 0; Enumerator enumerator = target.Fields.GetEnumerator(); try { while (enumerator.MoveNext()) { FieldDefinition current = enumerator.Current; if (current.IsStatic && current.HasConstant) { FieldDefinition val5 = new FieldDefinition(((MemberReference)current).Name, (FieldAttributes)32854, (TypeReference)(object)val3) { Constant = current.Constant }; val3.Fields.Add(val5); num++; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (num == 0) { refusal = ((MemberReference)target).FullName + " has no members to copy"; return null; } return val3; } private static FieldDefinition UnderlyingOf(TypeDefinition type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = type.Fields.GetEnumerator(); try { while (enumerator.MoveNext()) { FieldDefinition current = enumerator.Current; if (!current.IsStatic && ((MemberReference)current).Name == "value__") { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } private static MethodDefinition Parameterless(TypeDefinition type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (current.IsConstructor && !current.IsStatic && ((MethodReference)current).Parameters.Count == 0) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } internal static TypeDefinition Resolve(ModuleDefinition module, string fullName, string assembly) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown if (string.IsNullOrEmpty(fullName)) { return null; } TypeDefinition type = module.GetType(fullName); if (type != null) { return type; } if (!string.IsNullOrEmpty(assembly)) { AssemblyDefinition assembly2 = module.Assembly; object b; if (assembly2 == null) { b = null; } else { AssemblyNameDefinition name = assembly2.Name; b = ((name != null) ? ((AssemblyNameReference)name).Name : null); } if (!string.Equals(assembly, (string?)b, StringComparison.OrdinalIgnoreCase)) { try { AssemblyNameReference val = new AssemblyNameReference(assembly, new Version(0, 0, 0, 0)); IAssemblyResolver assemblyResolver = module.AssemblyResolver; object result; if (assemblyResolver == null) { result = null; } else { AssemblyDefinition obj = assemblyResolver.Resolve(val); if (obj == null) { result = null; } else { ModuleDefinition mainModule = obj.MainModule; result = ((mainModule != null) ? mainModule.GetType(fullName) : null); } } return (TypeDefinition)result; } catch { return null; } } } return null; } internal static MethodDefinition PointerConstructorOf(TypeDefinition type) { return PointerConstructor(type); } private static MethodDefinition PointerConstructor(TypeDefinition type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (current.IsConstructor && !current.IsStatic && ((MethodReference)current).Parameters.Count == 1 && (int)((ParameterReference)((MethodReference)current).Parameters[0]).ParameterType.MetadataType == 24) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return null; } internal static MethodDefinition PointerGetter(TypeDefinition type) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) TypeDefinition val = type; while (val != null) { Enumerator enumerator = val.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name == "get_Pointer" && ((MethodReference)current).Parameters.Count == 0) { return current; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } TypeDefinition val2 = null; try { TypeReference baseType = val.BaseType; val2 = ((baseType != null) ? baseType.Resolve() : null); } catch { } if (val2 == val) { return null; } val = val2; } return null; } internal static MethodReference On(GenericInstanceType instance, MethodDefinition definition) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0063: Expected O, but got Unknown MethodReference val = new MethodReference(((MemberReference)definition).Name, ((MethodReference)definition).ReturnType, (TypeReference)(object)instance) { HasThis = ((MethodReference)definition).HasThis, ExplicitThis = ((MethodReference)definition).ExplicitThis, CallingConvention = ((MethodReference)definition).CallingConvention }; Enumerator enumerator = ((MethodReference)definition).Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; val.Parameters.Add(new ParameterDefinition(((ParameterReference)current).ParameterType)); } return val; } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } } internal static class ShapeCoupling { private static readonly string[] Marks = new string[4] { "AppsCanvas", "GameplayMenu/Phone", "MainMenu/", "HomeScreen" }; private static readonly string[] Apps = new string[9] { "ProductManagerApp", "DeliveryApp", "MessagesApp", "ContactsApp", "ManagementApp", "OrganisationApp", "OrganizationApp", "SettingsApp", "MapApp" }; internal static void Check(ModuleDefinition module, ModReport report) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) try { Enumerator enumerator = module.Types.GetEnumerator(); try { while (enumerator.MoveNext()) { foreach (MethodDefinition item in Methods(enumerator.Current)) { Inspect(item, report); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } catch { } } private static IEnumerable Methods(TypeDefinition type) { Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { yield return enumerator.Current; } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } Enumerator enumerator2 = type.NestedTypes.GetEnumerator(); try { while (enumerator2.MoveNext()) { TypeDefinition current = enumerator2.Current; foreach (MethodDefinition item in Methods(current)) { yield return item; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } private static bool NamesTheGame(string text) { if (string.IsNullOrEmpty(text) || text.Length > 200) { return false; } string[] marks = Marks; foreach (string text2 in marks) { if (text == text2.TrimEnd('/')) { return true; } if (text.Contains('/') && text.Contains(text2)) { return true; } } return false; } private static string Shorten(string path) { int num = path.LastIndexOf('/'); if (num <= 0 || num >= path.Length - 1) { return path; } return path.Substring(num + 1); } private static void Inspect(MethodDefinition method, ModReport report) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (!method.HasBody) { return; } bool flag = false; string text = null; string text2 = null; Enumerator enumerator = method.Body.Instructions.GetEnumerator(); try { while (enumerator.MoveNext()) { Instruction current = enumerator.Current; if (current.OpCode == OpCodes.Ldstr && current.Operand is string text3) { if (text == null && NamesTheGame(text3)) { text = text3; } if (text2 != null) { continue; } string[] apps = Apps; foreach (string text4 in apps) { if (text3.Contains(text4)) { text2 = text4; break; } } } else { object operand = current.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val != null && ((MemberReference)val).Name == "Instantiate") { flag = true; } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (text != null && flag) { List findings = report.Findings; Finding obj = new Finding { Kind = "shape-coupled", Note = true, Symbol = (text2 ?? Shorten(text)), Reason = "this mod clones a piece of the game's own interface (" + Shorten(text) + ") and rebuilds what is inside it, so how it looks depends on the shape of something the game is free to change. Every name it asks for is here - if it looks wrong in game, that is why, and Polyfill cannot repair it" }; TypeDefinition declaringType = method.DeclaringType; obj.Site = ((declaringType != null) ? ((MemberReference)declaringType).FullName : null) + "/" + ((MemberReference)method).Name; findings.Add(obj); } } } internal static class StampFile { internal sealed class Entry { internal string Assembly; internal string OriginalSha; internal int Repairs; } internal sealed class Stamp { internal string Generator = ""; internal string Game = ""; internal string Polyfill = ""; internal readonly List Assemblies = new List(); internal bool Knows(string assembly) { foreach (Entry assembly2 in Assemblies) { if (string.Equals(assembly2.Assembly, assembly, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } internal const string FormatHeader = "# polyfill-stamp 1"; internal static string Path => System.IO.Path.Combine(Report.Directory, "interop.stamp"); internal static Stamp Read() { Stamp stamp = new Stamp(); try { if (!File.Exists(Path)) { return stamp; } string[] array = File.ReadAllLines(Path); if (array.Length == 0 || !array[0].StartsWith("# polyfill-stamp ", StringComparison.Ordinal)) { return stamp; } if (array[0] != "# polyfill-stamp 1") { return stamp; } string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string[] array3 = array2[i].Split('|'); switch (array3[0]) { case "G": if (array3.Length >= 2) { stamp.Generator = array3[1]; } break; case "V": if (array3.Length >= 3) { stamp.Game = array3[1]; stamp.Polyfill = array3[2]; } break; case "A": if (array3.Length >= 4) { stamp.Assemblies.Add(new Entry { Assembly = array3[1], OriginalSha = array3[2], Repairs = (int.TryParse(array3[3], out var result) ? result : 0) }); } break; } } } catch { } return stamp; } internal static void Write(string generatorDigest, IEnumerable assemblies) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# polyfill-stamp 1"); stringBuilder.AppendLine("# generated=" + DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")); stringBuilder.AppendLine("G|" + Escape(generatorDigest)); stringBuilder.AppendLine(string.Join("|", "V", Escape(Report.GameVersion()), Escape("0.11.16"))); foreach (Entry assembly in assemblies) { stringBuilder.AppendLine(string.Join("|", "A", Escape(assembly.Assembly), Escape(assembly.OriginalSha), assembly.Repairs.ToString())); } try { Directory.CreateDirectory(Report.Directory); File.WriteAllText(Path, stringBuilder.ToString()); } catch (Exception ex) { Instance log = Plugin.Log; if (log != null) { log.Warning("[stamp] could not be written: " + ex.Message); } } } internal static void Clear() { try { if (File.Exists(Path)) { File.Delete(Path); } } catch { } } private static string Escape(string value) { if (!string.IsNullOrEmpty(value)) { return value.Replace('|', '/').Replace('\r', ' ').Replace('\n', ' '); } return ""; } } internal static class Triage { private static readonly List _forwards = new List(); private static readonly List _members = new List(); private static readonly List _renames = new List(); internal static List Reports { get; private set; } = new List(); private static Dictionary Repair(string interopDirectory, InteropOriginals originals, ILog log) { Dictionary result = new Dictionary(StringComparer.Ordinal); if (_forwards.Count == 0 && _members.Count == 0 && _renames.Count == 0) { return result; } if (Plugin.DryRun) { log.Msg($"[inject] DryRun: {_forwards.Count + _members.Count + _renames.Count} repair(s) found and none applied. " + "Turn DryRun off in MelonPreferences to let them through."); return result; } HashSet hashSet = new HashSet(StringComparer.Ordinal); List list = new List(); foreach (InteropAugmentor.TypeForward forward in _forwards) { if (hashSet.Add(forward.Key)) { list.Add(forward); } } List list2 = new List(); foreach (InteropAugmentor.MemberForward member in _members) { if (hashSet.Add(member.Key)) { list2.Add(member); } } List list3 = new List(); foreach (InteropAugmentor.ParameterRename rename in _renames) { if (hashSet.Add(rename.Key)) { list3.Add(rename); } } InteropAugmentor.Result result2 = InteropAugmentor.Apply(interopDirectory, list, list2, list3, originals, log); foreach (string item in result2.Applied) { log.Msg("[inject] " + item); } foreach (string item2 in result2.Refused) { log.Warning("[inject] refused: " + item2); } StampFile.Write(originals.Generator.Digest(), result2.Stamped); return result2.Outcomes; } private static void RecordOutcomes(List reports, Dictionary outcomes) { if (outcomes.Count == 0) { return; } foreach (ModReport report in reports) { foreach (Finding finding in report.Findings) { if (finding.RepairKey != null && outcomes.TryGetValue(finding.RepairKey, out var value)) { int num = value.IndexOf(':'); finding.Outcome = ((num < 0) ? value : value.Substring(0, num)); finding.OutcomeDetail = ((num < 0) ? "" : value.Substring(num + 1)); } } } } internal static void Run(List candidates, ILog log) { string text = InteropIndex.LocateDirectory(); if (text == null) { log.Warning("[triage] the generated interop assemblies could not be found; skipping analysis."); return; } _forwards.Clear(); _members.Clear(); _renames.Clear(); List list = new List(candidates.Count); bool mayAct = !Plugin.DryRun && !Diagnostics.InteropAlreadyLoaded; InteropOriginals originals = InteropOriginals.Take(text, mayAct, log); string text2 = Registry.PastTheHorizon(GameVersionSource.Current); if (text2 != null) { log.Msg("[bridge] " + text2); } int assemblyCount; using (InteropIndex interopIndex = new InteropIndex(text, originals, LibraryDirectories(), SearchDirectories())) { foreach (ModCandidate candidate in candidates) { ModReport modReport = Analyse(candidate, interopIndex, log); if (modReport != null) { list.Add(modReport); } } assemblyCount = interopIndex.AssemblyCount; } Reports = list; SeedUnprompted(log); Dictionary outcomes = Repair(text, originals, log); RecordOutcomes(list, outcomes); Report.Write(list, text, assemblyCount, new List()); Summarise(list, log); } private static IEnumerable LibraryDirectories() { yield return MelonEnvironment.ModsDirectory; yield return MelonEnvironment.UserLibsDirectory; } private static IEnumerable SearchDirectories() { yield return MelonEnvironment.PluginsDirectory; yield return MelonEnvironment.OurRuntimeDirectory; } private static void CollectNamespaces(ModuleDefinition module, ModReport report) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(StringComparer.Ordinal); try { Enumerator enumerator = module.Types.GetEnumerator(); try { while (enumerator.MoveNext()) { string text = ((TypeReference)enumerator.Current).Namespace; if (!string.IsNullOrEmpty(text)) { int num = text.IndexOf('.'); string text2 = ((num > 0) ? text.Substring(0, num) : text); if (text2.Length >= 4) { hashSet.Add(text2); } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } catch { } foreach (string item in hashSet) { report.Namespaces.Add(item); } report.Namespaces.Sort(StringComparer.Ordinal); } private static ModReport Analyse(ModCandidate candidate, InteropIndex index, ILog log) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown ModReport modReport = new ModReport { Path = candidate.Path, AssemblyName = candidate.AssemblyName, Name = candidate.MelonName, Version = candidate.MelonVersion, Author = candidate.MelonAuthor }; try { ModuleDefinition val = ModuleDefinition.ReadModule(candidate.Path, new ReaderParameters { InMemory = true, ReadingMode = (ReadingMode)2, AssemblyResolver = index.Resolver }); try { CollectNamespaces(val, modReport); Dictionary repaired = new Dictionary(StringComparer.Ordinal); Dictionary standIns = new Dictionary(StringComparer.Ordinal); HashSet missingTypes = CheckTypes(val, index, modReport, repaired, standIns); CheckMembers(val, index, modReport, missingTypes, repaired, standIns); HarmonyTargets.Check(val, index, modReport); ShapeCoupling.Check(val, modReport); } finally { ((IDisposable)val)?.Dispose(); } } catch (Exception ex) { modReport.Findings.Add(new Finding { Kind = "read", Symbol = Path.GetFileName(candidate.Path), Reason = "could not be read: " + ex.Message }); log.Warning("[triage] " + candidate.Display + " could not be analysed: " + ex.Message); } return modReport; } private static List Answers(TypeRename renamed) { if (renamed?.Answers == null) { return null; } List list = new List(); Answer[] answers = renamed.Answers; foreach (Answer answer in answers) { list.Add(new FacadeTypes.Member { Name = answer.Name, Returns = answer.Returns, Takes = answer.Takes, Emit = answer.Emit }); } return list; } private static HashSet CheckTypes(ModuleDefinition module, InteropIndex index, ModReport report, Dictionary repaired, Dictionary standIns) { HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (TypeReference typeReference in module.GetTypeReferences()) { IMetadataScope scope = typeReference.Scope; string text = ((scope != null) ? scope.Name : null); if (!index.IsTracked(text)) { continue; } report.TypeRefs++; if (Resolve(typeReference, index) != null) { continue; } hashSet.Add(((MemberReference)typeReference).FullName); string text2 = ""; string reason = "type no longer exists in " + text; string repairKey = null; TypeDefinition val = null; Bridge bridge = Registry.Creator(text, ((MemberReference)typeReference).FullName); if (bridge != null) { report.Findings.Add(new Finding { Kind = ((index.Kind(text) == "game") ? "" : "library-") + "type", Scope = text, Symbol = ((MemberReference)typeReference).FullName, Reason = "type no longer exists in " + text + ", and nothing replaced it", Hint = "an empty stand-in, made by the rule for " + bridge.DeclaringType + "::" + bridge.OldName + ": " + bridge.Because, RepairKey = Key(bridge) }); continue; } TypeRename typeRename = Registry.FindType(text, ((MemberReference)typeReference).FullName); if (typeRename != null) { val = index.FindType(text, typeRename.NewFullName); if (val != null) { text2 = "hand-written rule: " + typeRename.Because; } else { reason = $"type no longer exists in {text}, and {typeRename.NewFullName} - what it " + "became in 0.4.6 - is not on this build either"; } } if (val == null && typeRename == null) { IReadOnlyList readOnlyList = index.BySimpleName(((MemberReference)typeReference).Name); if (readOnlyList.Count == 1) { val = readOnlyList[0]; text2 = ((MemberReference)val).FullName + " in " + ((AssemblyNameReference)((MemberReference)val).Module.Assembly.Name).Name; reason = "type moved"; } else if (readOnlyList.Count > 1) { reason = $"type no longer exists in {text}; {readOnlyList.Count} types share the name {((MemberReference)typeReference).Name}, so which one it became is not decidable here"; } } if (val != null) { repaired[((MemberReference)typeReference).FullName] = val; InteropAugmentor.TypeForward obj = new InteropAugmentor.TypeForward { InAssembly = text, Namespace = typeReference.Namespace, Name = ((MemberReference)typeReference).Name }; TypeReference obj2 = Root(((MemberReference)typeReference).DeclaringType); obj.NestedIn = ((obj2 != null) ? ((MemberReference)obj2).FullName : null); obj.TargetAssembly = ((AssemblyNameReference)((MemberReference)val).Module.Assembly.Name).Name; obj.TargetFullName = ((MemberReference)val).FullName; obj.ByNativeClass = typeRename?.ByNativeClass ?? false; obj.Answers = Answers(typeRename); InteropAugmentor.TypeForward typeForward = obj; _forwards.Add(typeForward); repairKey = typeForward.Key; if (typeForward.ByNativeClass) { standIns[((MemberReference)typeReference).FullName] = typeForward; } } bool covered = false; if (string.IsNullOrEmpty(text2)) { CoveredElsewhere.Entry entry = CoveredElsewhere.ForType(((MemberReference)typeReference).FullName); if (entry != null) { text2 = "covered by the fix " + entry.FixId + ": " + entry.Because; covered = true; } } report.Findings.Add(new Finding { Kind = ((index.Kind(text) == "game") ? "" : "library-") + "type", Scope = text, Symbol = ((MemberReference)typeReference).FullName, Reason = reason, Hint = text2, RepairKey = repairKey, Covered = covered }); } return hashSet; } private static void CheckMembers(ModuleDefinition module, InteropIndex index, ModReport report, HashSet missingTypes, Dictionary repaired, Dictionary standIns) { foreach (MemberReference memberReference in module.GetMemberReferences()) { TypeReference val = Root(memberReference.DeclaringType); object obj; if (val == null) { obj = null; } else { IMetadataScope scope = val.Scope; obj = ((scope != null) ? scope.Name : null); } string text = (string)obj; if (!index.IsTracked(text)) { continue; } report.MemberRefs++; TypeDefinition value = Resolve(val, index); if (value == null && val != null) { repaired.TryGetValue(((MemberReference)val).FullName, out value); } if ((value == null && val != null && missingTypes.Contains(((MemberReference)val).FullName)) || value == null) { continue; } if (val != null && standIns.TryGetValue(((MemberReference)val).FullName, out var value2)) { CheckStandIn(memberReference, value2, ((MemberReference)val).FullName, (index.Kind(text) == "game") ? "" : "library-", text, report); continue; } string kindPrefix = ((index.Kind(text) == "game") ? "" : "library-"); MethodReference val2 = (MethodReference)(object)((memberReference is MethodReference) ? memberReference : null); if (val2 != null) { CheckMethod(val2, value, text, kindPrefix, report, index, repaired); continue; } FieldReference val3 = (FieldReference)(object)((memberReference is FieldReference) ? memberReference : null); if (val3 != null) { CheckField(val3, value, text, kindPrefix, report, index); } } } private static void CheckStandIn(MemberReference wanted, InteropAugmentor.TypeForward standIn, string oldFullName, string kindPrefix, string scope, ModReport report) { MethodReference val = (MethodReference)(object)((wanted is MethodReference) ? wanted : null); if (val != null) { foreach (FacadeTypes.Member item in standIn.Answers ?? new List()) { if (item.Name != ((MemberReference)val).Name) { continue; } string[] array = item.Takes ?? Array.Empty(); if (val.Parameters.Count == array.Length) { bool flag = true; for (int i = 0; i < array.Length && flag; i++) { flag = ((MemberReference)((ParameterReference)val.Parameters[i]).ParameterType).FullName == array[i]; } if (flag) { return; } } } report.Findings.Add(new Finding { Kind = kindPrefix + "member", Scope = scope, Symbol = oldFullName + "::" + ((MemberReference)val).Name + "(" + Shape(val) + ")", Reason = "the name is put back as a class around " + standIn.TargetFullName + "'s native class, and that stand-in does not carry this member" }); } else { report.Findings.Add(new Finding { Kind = kindPrefix + "field", Scope = scope, Symbol = oldFullName + "::" + wanted.Name, Reason = "the name is put back as a class around " + standIn.TargetFullName + "'s native class, and a stand-in of that kind carries no fields" }); } } private static string Shape(MethodReference call) { //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) List list = new List(call.Parameters.Count); Enumerator enumerator = call.Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; list.Add(((MemberReference)((ParameterReference)current).ParameterType).FullName); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return string.Join(", ", list); } private static bool Has(TypeDefinition type, string name) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { if (((MemberReference)enumerator.Current).Name == name) { return true; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return false; } private static IEnumerable Chain(TypeDefinition type, InteropIndex index) { HashSet seen = new HashSet(StringComparer.Ordinal); TypeDefinition current = type; while (current != null && seen.Add(((MemberReference)current).FullName)) { yield return current; if (current.BaseType == null) { break; } current = Resolve(Root(current.BaseType), index); } } private static TypeDefinition Inherits(TypeDefinition declaring, MethodReference wanted, InteropIndex index) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) bool flag = true; foreach (TypeDefinition item in Chain(declaring, index)) { if (flag) { flag = false; continue; } Enumerator enumerator2 = item.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { MethodDefinition current2 = enumerator2.Current; if (((MemberReference)current2).Name == ((MemberReference)wanted).Name && NameHeuristics.SameParameters(wanted, current2)) { return item; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } return null; } private static string Nearby(TypeDefinition declaring, string name, InteropIndex index) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) bool flag = true; foreach (TypeDefinition item in Chain(declaring, index)) { if (flag) { flag = false; continue; } Enumerator enumerator2 = item.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { if (((MemberReference)enumerator2.Current).Name == name) { return ((MemberReference)item).Name + " has " + name + " under different parameters"; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } List list = NameHeuristics.ForMethod(item, name, null); if (list.Count != 1) { continue; } return ((MemberReference)item).Name + " has " + list[0].NewName; } return null; } private static void CheckMethod(MethodReference wanted, TypeDefinition declaring, string scope, string kindPrefix, ModReport report, InteropIndex index, Dictionary repaired) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) bool flag = false; Enumerator enumerator = declaring.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (((MemberReference)current).Name != ((MemberReference)wanted).Name) { continue; } flag = true; if (!NameHeuristics.SameParameters(wanted, current)) { continue; } TypeReference returnType = wanted.ReturnType; string text = ((returnType != null) ? ((MemberReference)returnType).FullName : null); if (text != null && repaired.ContainsKey(text)) { TypeReference returnType2 = ((MethodReference)current).ReturnType; if (!string.Equals(text, (returnType2 != null) ? ((MemberReference)returnType2).FullName : null, StringComparison.Ordinal)) { string text2 = ((kindPrefix.Length == 0) ? Collect(new InteropAugmentor.MemberForward { InAssembly = scope, DeclaringType = ((MemberReference)declaring).FullName, OldName = ((MemberReference)wanted).Name, NewName = ((MemberReference)current).Name, ParameterCount = (wanted.Parameters?.Count ?? 0), ParameterTypes = ParameterTypes(wanted), SameNameNewReturn = true, Rule = "return type" }) : null); List findings = report.Findings; Finding obj = new Finding { Kind = kindPrefix + "member", Scope = scope, Symbol = ((MemberReference)declaring).FullName + "::" + ((MemberReference)wanted).Name + Signature(wanted) }; TypeReference returnType3 = ((MethodReference)current).ReturnType; obj.Reason = "the method is here and hands back " + (((returnType3 != null) ? ((MemberReference)returnType3).Name : null) ?? "something else") + " from where that type moved to, so a call naming the old one does not resolve"; obj.Hint = ((text2 == null) ? "" : "the same method, declared to hand back the name the mod knows"); obj.RepairKey = text2; findings.Add(obj); } } return; } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (Inherits(declaring, wanted, index) != null) { return; } TypeDefinition val = declaring; List list = NameHeuristics.ForMethod(declaring, ((MemberReference)wanted).Name, wanted); if (list.Count == 0) { foreach (TypeDefinition item in Chain(declaring, index)) { if (item != declaring) { List list2 = NameHeuristics.ForMethod(item, ((MemberReference)wanted).Name, wanted); if (list2.Count != 0) { list = list2; val = item; break; } } } } string text3 = ((list.Count == 1) ? (list[0].NewName + " [" + list[0].Rule + "]") : ""); int num = wanted.Parameters?.Count ?? 0; string repairKey = null; string[] parameterTypes = ParameterTypes(wanted); Bridge bridge = ((kindPrefix.Length == 0) ? Registry.Find(scope, ((MemberReference)declaring).FullName, ((MemberReference)wanted).Name, num, parameterTypes) : null); if (bridge != null) { text3 = "hand-written rule: " + bridge.Because; repairKey = Collect(new InteropAugmentor.MemberForward { InAssembly = bridge.Assembly, DeclaringType = bridge.DeclaringType, OldName = bridge.OldName, NewName = null, ParameterCount = bridge.ParameterCount, ParameterTypes = bridge.ParameterTypes, Rule = "curated" }); } else if (kindPrefix.Length == 0) { string text4 = AliasDb.Successor(((MemberReference)declaring).FullName, ((MemberReference)wanted).Name, num, Report.GameVersion()); if (text4 != null && Has(declaring, text4)) { text3 = text4 + " [version history]"; repairKey = Collect(new InteropAugmentor.MemberForward { InAssembly = scope, DeclaringType = ((MemberReference)declaring).FullName, OldName = ((MemberReference)wanted).Name, NewName = text4, ParameterCount = num, Rule = "version history" }); } else if (list.Count == 1 && list[0].Member is MethodDefinition) { repairKey = Collect(new InteropAugmentor.MemberForward { InAssembly = scope, DeclaringType = ((MemberReference)val).FullName, OldName = ((MemberReference)wanted).Name, NewName = list[0].NewName, ParameterCount = num, Rule = list[0].Rule }); } } string text5 = (flag ? "the method still exists but its parameters changed" : ((list.Count > 1) ? $"method missing; {list.Count} members could be meant, so none is chosen" : "method missing, with nothing on this type to point at")); if (!flag && string.IsNullOrEmpty(text3)) { string text6 = Nearby(declaring, ((MemberReference)wanted).Name, index); if (text6 != null) { text5 = text5 + "; the base type " + text6; } } CoveredElsewhere.Entry entry = CoveredElsewhere.For(((MemberReference)declaring).FullName, ((MemberReference)wanted).Name); if (entry != null && string.IsNullOrEmpty(text3)) { text3 = "covered by the fix " + entry.FixId + ": " + entry.Because; } report.Findings.Add(new Finding { Kind = kindPrefix + "member", Scope = scope, Symbol = ((MemberReference)declaring).FullName + "::" + ((MemberReference)wanted).Name + Signature(wanted, flag), Reason = text5, Hint = text3, RepairKey = repairKey, Covered = (entry != null) }); } private static void CheckField(FieldReference wanted, TypeDefinition declaring, string scope, string kindPrefix, ModReport report, InteropIndex index) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) foreach (TypeDefinition item in Chain(declaring, index)) { Enumerator enumerator2 = item.Fields.GetEnumerator(); try { while (enumerator2.MoveNext()) { if (((MemberReference)enumerator2.Current).Name == ((MemberReference)wanted).Name) { return; } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } List list = NameHeuristics.ForField(declaring, ((MemberReference)wanted).Name); TypeDefinition val = ((list.Count > 0) ? declaring : null); if (list.Count == 0) { foreach (TypeDefinition item2 in Chain(declaring, index)) { if (item2 != declaring) { list = NameHeuristics.ForField(item2, ((MemberReference)wanted).Name); if (list.Count > 0) { val = item2; break; } } } } string text = ((val == null || val == declaring) ? "" : (" on " + ((MemberReference)val).Name)); string hint = ((list.Count == 1) ? (list[0].NewName + text + " [" + list[0].Rule + "]") : ""); string reason = ((list.Count > 1) ? $"field missing; {list.Count} members could be meant, so none is chosen" : ((list.Count == 1 && list[0].KindChanged) ? ("the field became a property" + text + ", and a field cannot be answered with one - the mod needs rebuilding against the MelonLoader it runs on") : "field missing, with nothing on this type to point at")); report.Findings.Add(new Finding { Kind = kindPrefix + "field", Scope = scope, Symbol = ((MemberReference)declaring).FullName + "::" + ((MemberReference)wanted).Name, Reason = reason, Hint = hint }); } private static void SeedUnprompted(ILog log) { HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (InteropAugmentor.MemberForward member in _members) { hashSet.Add(member.Key); } int num = 0; foreach (Bridge item in Registry.Bridges()) { if (item.Unprompted) { InteropAugmentor.MemberForward memberForward = new InteropAugmentor.MemberForward { InAssembly = item.Assembly, DeclaringType = item.DeclaringType, OldName = item.OldName, NewName = null, ParameterCount = item.ParameterCount, ParameterTypes = item.ParameterTypes, Rule = "curated" }; if (hashSet.Add(memberForward.Key)) { Collect(memberForward); num++; } } } if (num > 0) { log.Msg($"[triage] {num} repair(s) asked for without a mod naming them, because the mods " + "that need them reach the member by reflection."); } } private static string Collect(InteropAugmentor.MemberForward member) { _members.Add(member); return member.Key; } private static string Key(Bridge bridge) { return new InteropAugmentor.MemberForward { InAssembly = bridge.Assembly, DeclaringType = bridge.DeclaringType, OldName = bridge.OldName, ParameterCount = bridge.ParameterCount, ParameterTypes = bridge.ParameterTypes }.Key; } internal static string Request(InteropAugmentor.MemberForward member) { return Collect(member); } internal static string RequestRename(InteropAugmentor.ParameterRename rename) { _renames.Add(rename); return rename.Key; } internal static TypeReference Root(TypeReference reference) { while (true) { TypeSpecification val = (TypeSpecification)(object)((reference is TypeSpecification) ? reference : null); if (val == null) { break; } reference = val.ElementType; } return reference; } internal static TypeDefinition Resolve(TypeReference reference, InteropIndex index) { if (reference == null) { return null; } IMetadataScope scope = reference.Scope; TypeDefinition val = index.FindType((scope != null) ? scope.Name : null, ((MemberReference)reference).FullName); if (val != null) { return val; } try { return reference.Resolve(); } catch { return null; } } private static string[] ParameterTypes(MethodReference method) { if (((method != null) ? method.Parameters : null) == null) { return Array.Empty(); } string[] array = new string[method.Parameters.Count]; for (int i = 0; i < array.Length; i++) { int num = i; TypeReference parameterType = ((ParameterReference)method.Parameters[i]).ParameterType; array[num] = ((parameterType != null) ? ((MemberReference)parameterType).FullName : null) ?? "?"; } return array; } private static string Signature(MethodReference method, bool full = false) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (method.HasParameters) { Enumerator enumerator = method.Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; object obj; if (!full) { TypeReference parameterType = ((ParameterReference)current).ParameterType; obj = ((parameterType != null) ? ((MemberReference)parameterType).Name : null); } else { TypeReference parameterType2 = ((ParameterReference)current).ParameterType; obj = ((parameterType2 != null) ? ((MemberReference)parameterType2).FullName : null); } if (obj == null) { obj = "?"; } list.Add((string)obj); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } return "(" + string.Join(", ", list) + ")"; } private static void Summarise(List reports, ILog log) { int num = 0; int num2 = 0; int num3 = 0; foreach (ModReport report in reports) { string verdict = report.Verdict; if (!(verdict == "clean")) { if (verdict == "adaptable") { num2++; } else { num3++; } } else { num++; } } int num4 = 0; int num5 = 0; int num6 = 0; foreach (ModReport report2 in reports) { num4 += report2.TypeRefs; num5 += report2.MemberRefs; num6 += report2.HarmonyTargetsChecked; } log.Msg($"[triage] Schedule I {Report.GameVersion()} - {reports.Count} mod(s): {num} need nothing, {num2} could be adapted, {num3} ask for something that is gone."); log.Msg($"[triage] checked {num4} type references, {num5} member references and {num6} Harmony targets."); foreach (ModReport report3 in reports) { if (report3.Verdict == "clean") { continue; } int num7 = 0; foreach (Finding finding in report3.Findings) { if (!string.IsNullOrEmpty(finding.Hint)) { num7++; } } log.Warning($"[triage] {report3.Name ?? report3.AssemblyName} {report3.Version} - {report3.Findings.Count} missing, {num7} with something to try"); } if (reports.Count > 0) { log.Msg("[triage] Type `polyfill` in the console for the full list, or read " + Report.LastRunPath); } } } } namespace Polyfill.Boot { internal static class DeclaredMethodFallback { private const string Id = "doodesch.polyfill.declaredmethod"; internal static void Install(Instance log) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00a8: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(AccessTools), "DeclaredMethod", new Type[4] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }, (Type[])null); if (methodInfo == null) { log.Warning("[harmony] AccessTools.DeclaredMethod is not where it was, so patches aimed at a renamed type will not find it. Repairs are unaffected."); return; } Harmony val = new Harmony("doodesch.polyfill.declaredmethod"); val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DeclaredMethodFallback), "Unambiguous", (Type[])null), new HarmonyMethod(typeof(DeclaredMethodFallback), "Fallback", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo2 = AccessTools.Method(typeof(AccessTools), "DeclaredProperty", new Type[2] { typeof(Type), typeof(string) }, (Type[])null); if (methodInfo2 != null) { val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(DeclaredMethodFallback), "ForProperty", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } log.Msg("[harmony] a patch aimed at a type this build renamed will be pointed at the member the game has."); } catch (Exception ex) { log.Warning("[harmony] could not install the lookup fallback: " + ex.Message); } } private static void Fallback(Type type, string name, Type[] parameters, Type[] generics, ref MethodInfo __result) { if (__result != null || type == null || name == null) { return; } string text = RenamedMethods.Successor(type.FullName, name); if (text != null) { try { MethodInfo methodInfo = AccessTools.Method(type, text, parameters, generics); if (methodInfo != null) { __result = Canonical(methodInfo); return; } } catch { } } if (!RenamedTypes.IsStandIn(type.FullName)) { return; } try { MethodInfo methodInfo2 = AccessTools.Method(type, name, parameters, generics); if (!(methodInfo2 == null) && !(methodInfo2.DeclaringType == type)) { __result = Canonical(methodInfo2); } } catch { } } private static MethodInfo Canonical(MethodInfo method) { if (method?.DeclaringType == null) { return method; } if (method.ReflectedType == method.DeclaringType) { return method; } try { return AccessTools.DeclaredMethod(method.DeclaringType, method.Name, Types(method.GetParameters()), (Type[])null) ?? method; } catch { return method; } } private static Type[] Types(ParameterInfo[] parameters) { Type[] array = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { array[i] = parameters[i].ParameterType; } return array; } private static bool Unambiguous(Type type, string name, Type[] parameters, ref MethodInfo __result) { if (type == null || name == null || parameters != null) { return true; } if (!GrownOverloads.Doubled(type.FullName, name)) { return true; } try { MethodInfo methodInfo = null; MethodInfo[] methods = type.GetMethods(AccessTools.all); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2.Name != name) && !(methodInfo2.DeclaringType != type) && !GrownOverloads.IsStandIn(type.FullName, name, methodInfo2.GetParameters().Length)) { if (methodInfo != null) { return true; } methodInfo = methodInfo2; } } if (methodInfo == null) { return true; } __result = methodInfo; return false; } catch { return true; } } private static void ForProperty(Type type, string name, ref PropertyInfo __result) { if (__result != null || type == null || name == null || !RenamedTypes.IsStandIn(type.FullName)) { return; } try { PropertyInfo propertyInfo = AccessTools.Property(type, name); if (!(propertyInfo == null) && !(propertyInfo.DeclaringType == type)) { __result = propertyInfo; } } catch { } } } internal static class Diagnostics { private static readonly string[] Watched = new string[5] { "Assembly-CSharp", "Assembly-CSharp-firstpass", "Il2CppScheduleOne.Core", "Il2CppFishNet.Runtime", "Il2Cppmscorlib" }; internal static bool InteropAlreadyLoaded { get; private set; } internal static void RecordInteropLoadState(Instance log) { List list = new List(); try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string name; try { name = assembly.GetName().Name; } catch { continue; } string[] watched = Watched; foreach (string b in watched) { if (string.Equals(name, b, StringComparison.OrdinalIgnoreCase)) { list.Add(name); } } } } catch (Exception ex) { log.Warning("[m1] could not enumerate loaded assemblies: " + ex.Message); return; } InteropAlreadyLoaded = list.Count > 0; string text = InteropIndex.LocateDirectory(); int value = 0; try { if (text != null && Directory.Exists(text)) { value = Directory.GetFiles(text, "*.dll").Length; } } catch { } if (list.Count == 0) { log.Msg($"[m1] no interop assembly is loaded yet - the window is open ({value} in {text})."); } else { log.Warning($"[m1] {list.Count} interop assembly/assemblies are ALREADY loaded at this point: " + string.Join(", ", list) + ". Changes to those files take effect on the next launch, not this one."); } } } internal static class FirstAsk { private delegate bool EnumWindow(IntPtr window, IntPtr extra); private const int Attempts = 3; private const int DeadlineSeconds = 60; private const uint YesNo = 4u; private const uint IconQuestion = 32u; private const uint DefaultSecond = 256u; private const uint TopMost = 262144u; private const uint SetForeground = 65536u; private const int IdYes = 6; private const int WmClose = 16; private const string Question = "Send anonymous telemetry to help fix broken mods?\n\nWhich mods Polyfill repaired, which it could not, and any errors\nthey threw while you played.\n\nMod names, versions and authors, how long you played, and a random\nnumber for this install. Never your name, your save or your folders."; [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int MessageBoxW(IntPtr owner, string text, string caption, uint type); [DllImport("user32.dll")] private static extern bool EnumThreadWindows(uint threadId, EnumWindow callback, IntPtr extra); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr SendMessageW(IntPtr window, int message, IntPtr w, IntPtr l); [DllImport("kernel32.dll")] private static extern uint GetCurrentThreadId(); internal static void Once(Instance log) { Consent.State state = Consent.Read(); if (state.Answered || state.Asked >= 3) { return; } if (Headless.Yes(out var why)) { log.Msg($"[share] not asking - {why}. Nothing is shared. To send findings from this server, set {"ShareFindings"} = true under [Polyfill] in " + "UserData/MelonPreferences.cfg."); return; } Consent.CountOneAsk(state); int num = AskWithDeadline(log); bool flag = num == 6; log.Msg($"[share] the dialog returned {num} " + num switch { 7 => "(No)", 6 => "(Yes)", _ => "(no answer)", }); Consent.Write(flag, num != 0); if (num == 0) { log.Msg("[share] nobody answered, so nothing is shared. Asking again next launch " + $"({state.Asked + 1} of {3}), or turn it on with `polyfillshare on`."); } else { log.Msg(flag ? "[share] on - anonymous findings will be sent. `polyfillshare off` stops it." : "[share] off - nothing is sent. `polyfillshare on` turns it on."); } } private static int AskWithDeadline(Instance log) { int answer = 0; uint dialogThread = 0u; ManualResetEventSlim done = new ManualResetEventSlim(initialState: false); Thread thread = new Thread((ThreadStart)delegate { dialogThread = GetCurrentThreadId(); try { answer = MessageBoxW(IntPtr.Zero, "Send anonymous telemetry to help fix broken mods?\n\nWhich mods Polyfill repaired, which it could not, and any errors\nthey threw while you played.\n\nMod names, versions and authors, how long you played, and a random\nnumber for this install. Never your name, your save or your folders.", "Polyfill", 327972u); } catch (Exception ex) { log.Warning("[share] the question could not be shown, so nothing is shared: " + ex.Message); } finally { done.Set(); } }); thread.IsBackground = true; thread.Name = "Polyfill consent"; thread.SetApartmentState(ApartmentState.STA); thread.Start(); if (done.Wait(TimeSpan.FromSeconds(60.0))) { return answer; } try { if (dialogThread != 0) { EnumThreadWindows(dialogThread, delegate(IntPtr window, IntPtr _) { SendMessageW(window, 16, IntPtr.Zero, IntPtr.Zero); return true; }, IntPtr.Zero); } } catch { } done.Wait(TimeSpan.FromSeconds(5.0)); return 0; } } internal static class FolderScan { internal static bool Mirrored { get; private set; } internal static List ModDirectories(Instance log) { List list = TryMirror(log); if (list != null) { Mirrored = true; return list; } Mirrored = false; log.Warning("[scan] MelonLoader's own mod-directory list could not be read; falling back to a reimplementation of ScanForFolders. If a mod fails to load, this is the first suspect."); return Rebuild(); } private static List TryMirror(Instance log) { try { if (!(typeof(MelonFolderHandler).GetField("_modDirs", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) is List collection)) { return null; } return new List(collection); } catch (Exception ex) { log.Warning("[scan] could not mirror MelonFolderHandler._modDirs: " + ex.Message); return null; } } private static List Rebuild() { List list = new List(); string modsDirectory = MelonEnvironment.ModsDirectory; if (string.IsNullOrEmpty(modsDirectory) || !Directory.Exists(modsDirectory)) { return list; } list.Add(modsDirectory); Walk(modsDirectory, requireManifest: true, list); return list; } private static void Walk(string path, bool requireManifest, List into) { if (DisableSubFolderLoad()) { return; } string[] directories; try { directories = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly); } catch { return; } string[] array = directories; foreach (string text in array) { if (Directory.Exists(text)) { string fileName = Path.GetFileName(text); if (!IsNameExcluded(fileName) && !(fileName == "UserLibs") && !(fileName == "Plugins") && (!requireManifest || DisableSubFolderManifest() || File.Exists(Path.Combine(text, "manifest.json")))) { into.Add(text); Walk(text, requireManifest: false, into); } } } } private static bool IsNameExcluded(string name) { if (!name.StartsWith("~") && !name.StartsWith(".") && !(name == "Broken") && !(name == "Retired")) { return name == "Disabled"; } return true; } private static bool DisableSubFolderLoad() { return LoaderFlag("DisableSubFolderLoad"); } private static bool DisableSubFolderManifest() { return LoaderFlag("DisableSubFolderManifest"); } private static bool LoaderFlag(string name) { try { object obj = typeof(MelonFolderHandler).Assembly.GetType("MelonLoader.LoaderConfig")?.GetProperty("Current", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); object obj2 = obj?.GetType().GetProperty("Loader")?.GetValue(obj); object obj3 = obj2?.GetType().GetProperty(name)?.GetValue(obj2); bool flag = default(bool); int num; if (obj3 is bool) { flag = (bool)obj3; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } } internal static class InteropTypeSweep { private sealed class Sweep { internal string Type; internal string Method; internal string Mod; internal Type[] Takes; internal string Answer; internal string Anchor; } private static readonly Sweep[] Known = new Sweep[1] { new Sweep { Type = "CustomCommandsFramework.CustomCommandsHelper", Method = "GetSafeTypes", Mod = "Custom Commands Framework" } }; private static readonly Sweep[] KnownSelfSweeps = new Sweep[1] { new Sweep { Type = "S1API.Entities.NPC", Method = "PreRegisterAllNpcPrefabsInternal", Mod = "S1API", Anchor = "S1API" } }; private static readonly Sweep[] KnownSearches = new Sweep[3] { new Sweep { Type = "UltimateModMenu.Core.ReflectionUtil", Method = "FindTypeBySuffix", Mod = "Ultimate Mod Menu", Takes = new Type[1] { typeof(string) }, Answer = "Search" }, new Sweep { Type = "UltimateModMenu.Workforce.GameTypeFinder", Method = "Find", Mod = "Ultimate Mod Menu", Takes = new Type[2] { typeof(string), typeof(string[]) }, Answer = "FindByName" }, new Sweep { Type = "UltimateModMenu.Core.ReflectionUtil", Method = "FindType", Mod = "Ultimate Mod Menu", Takes = new Type[1] { typeof(string[]) }, Answer = "FindByNames" } }; private static Instance _log; private static string _interop; private static int _skipped; private static int _searched; private static readonly Dictionary> Names = new Dictionary>(); private static int _replaced; private static string _anchor; private static bool _said; private static readonly HashSet Complained = new HashSet(StringComparer.Ordinal); internal static void Install(Instance log, string interopDirectory) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Expected O, but got Unknown //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_0482: Expected O, but got Unknown _log = log; _interop = interopDirectory; if (string.IsNullOrEmpty(_interop)) { return; } Harmony val = new Harmony("doodesch.polyfill.sweeps"); Sweep[] known = Known; foreach (Sweep sweep in known) { try { Type type = AccessTools.TypeByName(sweep.Type); if (!(type == null)) { MethodInfo methodInfo = AccessTools.Method(type, sweep.Method, new Type[1] { typeof(Assembly) }, (Type[])null); if (methodInfo == null) { log.Warning($"[sweep] {sweep.Mod} has no {sweep.Method}(Assembly) here, so its walk " + "over the interop assemblies is not guarded. If the game dies on startup with no message, that is where to look."); } else { val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(InteropTypeSweep), "Skip", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.Msg("[sweep] " + sweep.Mod + " will not be handed an interop assembly to enumerate; doing that kills the process without a message."); } } } catch (Exception ex) { log.Warning("[sweep] could not guard " + sweep.Mod + ": " + ex.Message); } } known = KnownSearches; foreach (Sweep sweep2 in known) { try { Type type2 = AccessTools.TypeByName(sweep2.Type); if (!(type2 == null)) { MethodInfo methodInfo2 = AccessTools.Method(type2, sweep2.Method, sweep2.Takes, (Type[])null); if (methodInfo2 == null) { log.Warning($"[sweep] {sweep2.Mod} has no {sweep2.Type}.{sweep2.Method} of that " + "shape here, so its search over every loaded assembly is not guarded. If the game dies on startup with no message, that is where to look."); } else { val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(InteropTypeSweep), sweep2.Answer, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.Msg($"[sweep] {sweep2.Mod} ({sweep2.Method}) searches for types by name without " + "enumerating the game's generated assemblies; doing that kills the process without a message."); } } } catch (Exception ex2) { log.Warning("[sweep] could not guard " + sweep2.Mod + ": " + ex2.Message); } } known = KnownSelfSweeps; foreach (Sweep sweep3 in known) { try { Type type3 = AccessTools.TypeByName(sweep3.Type); if (type3 == null) { continue; } MethodInfo methodInfo3 = AccessTools.DeclaredMethod(type3, sweep3.Method, Type.EmptyTypes, (Type[])null); if (methodInfo3 == null) { log.Warning($"[sweep] {sweep3.Mod} has no {sweep3.Method}() here, so its walk over " + "every loaded assembly is not guarded. If the game dies on startup with no message, that is where to look."); continue; } if (_anchor != null && _anchor != sweep3.Anchor) { log.Warning($"[sweep] {sweep3.Mod}.{sweep3.Method}() looks for {sweep3.Anchor} but the filter is already set to {_anchor}, so it was not guarded."); continue; } _anchor = sweep3.Anchor; _replaced = 0; val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(InteropTypeSweep), "WithoutInterop", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); if (_replaced != 1) { log.Warning($"[sweep] {sweep3.Mod}.{sweep3.Method}() calls AppDomain.GetAssemblies {_replaced} time(s) where this expected exactly one, so it was not " + "guarded. The crash it protects against is still possible."); } else { log.Msg($"[sweep] {sweep3.Mod} will only walk the loaded assemblies that name {sweep3.Anchor}; enumerating one of the others can kill the process " + "without a message."); } } catch (Exception ex3) { log.Warning("[sweep] could not guard " + sweep3.Mod + ": " + ex3.Message); } } } private static bool Search(string requested, ref Type __result) { __result = null; try { string suffix = requested; if (requested.IndexOf('.') >= 0 && requested.StartsWith("Il2Cpp", StringComparison.Ordinal)) { suffix = requested.Substring("Il2Cpp".Length); } __result = InInterop(requested, suffix) ?? Elsewhere(requested, suffix); if (++_searched == 1) { Instance log = _log; if (log != null) { log.Msg("[sweep] answered a mod's type search from the game's assembly metadata instead of letting it load every type there is. Reading them that way is what takes the process down."); } } } catch (Exception ex) { Instance log2 = _log; if (log2 != null) { log2.Warning("[sweep] type search failed: " + ex.Message); } } return false; } private static bool FindByName(string simpleName, string[] fullNames, ref Type __result) { __result = null; try { string[] array = fullNames ?? Array.Empty(); foreach (string fullName in array) { __result = Named(fullName); if (__result != null) { Announce(); return false; } } __result = InInterop(simpleName, null) ?? Elsewhere(simpleName, null); Announce(); } catch (Exception ex) { Instance log = _log; if (log != null) { log.Warning("[sweep] type search failed: " + ex.Message); } } return false; } private static bool FindByNames(string[] names, ref Type __result) { __result = null; try { string[] array = names ?? Array.Empty(); foreach (string fullName in array) { __result = Named(fullName); if (__result != null) { break; } } Announce(); } catch (Exception ex) { Instance log = _log; if (log != null) { log.Warning("[sweep] type search failed: " + ex.Message); } } return false; } private static Type Named(string fullName) { if (string.IsNullOrEmpty(fullName)) { return null; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { if (IsInterop(assembly)) { string text = Exactly(assembly, fullName); if (text != null) { Type type = assembly.GetType(text, throwOnError: false, ignoreCase: false); if (type != null) { return type; } } } else { Type type2 = assembly.GetType(fullName, throwOnError: false, ignoreCase: true); if (type2 != null) { return type2; } } } catch { } } return null; } private static string Exactly(Assembly assembly, string fullName) { foreach (string item in NamesOf(assembly)) { if (item.Equals(fullName, StringComparison.OrdinalIgnoreCase)) { return item; } } return null; } private static void Announce() { if (++_searched == 1) { Instance log = _log; if (log != null) { log.Msg("[sweep] answered a mod's type search from the game's assembly metadata instead of letting it load every type there is. Reading them that way is what takes the process down."); } } } private static Type InInterop(string requested, string suffix) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!IsInterop(assembly)) { continue; } string text = NameIn(assembly, requested, suffix); if (text == null) { continue; } try { Type type = assembly.GetType(text, throwOnError: false, ignoreCase: false); if (type != null) { return type; } } catch { } } return null; } private static string NameIn(Assembly assembly, string requested, string suffix) { foreach (string item in NamesOf(assembly)) { if (item.Equals(requested, StringComparison.OrdinalIgnoreCase)) { return item; } int num = item.LastIndexOf('.'); string text = ((num < 0) ? item : item.Substring(num + 1)); if (suffix != null && item.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) { return item; } if (text.Equals(requested, StringComparison.OrdinalIgnoreCase)) { return item; } } return null; } private static List NamesOf(Assembly assembly) { if (Names.TryGetValue(assembly, out var value)) { return value; } value = ReadNames(assembly); Names[assembly] = value; return value; } private static List ReadNames(Assembly assembly) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); try { ModuleDefinition val = ModuleDefinition.ReadModule(assembly.Location); try { Enumerator enumerator = val.Types.GetEnumerator(); try { while (enumerator.MoveNext()) { TypeDefinition current = enumerator.Current; if (current.IsPublic) { list.Add(((MemberReference)current).FullName); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } finally { ((IDisposable)val)?.Dispose(); } } catch (Exception ex) { Instance log = _log; if (log != null) { log.Warning("[sweep] could not read " + assembly.GetName().Name + ": " + ex.Message); } } return list; } private static Type Elsewhere(string requested, string suffix) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (IsInterop(assembly)) { continue; } Type[] array; Type[] types; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { List list = new List(); types = ex.Types; foreach (Type type in types) { if (type != null) { list.Add(type); } } array = list.ToArray(); } catch { continue; } types = array; foreach (Type type2 in types) { string text = type2.FullName ?? type2.Name; if (text.Equals(requested, StringComparison.OrdinalIgnoreCase)) { return type2; } if (suffix != null && text.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) { return type2; } if (type2.Name.Equals(requested, StringComparison.OrdinalIgnoreCase)) { return type2; } } } return null; } private static bool Skip(Assembly assembly, ref IEnumerable __result) { if (!IsInterop(assembly)) { return true; } __result = Array.Empty(); if (++_skipped == 1) { Instance log = _log; if (log != null) { log.Msg("[sweep] skipped the game's generated assemblies while a mod enumerated types. They carry no mod commands, and reading them that way is what takes the process down."); } } return false; } private static bool IsInterop(Assembly assembly) { if (assembly == null) { return false; } try { if (assembly.IsDynamic) { return false; } string location = assembly.Location; if (string.IsNullOrEmpty(location)) { return false; } return string.Equals(Path.GetDirectoryName(location), _interop.TrimEnd(Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase); } catch { return false; } } private static IEnumerable WithoutInterop(IEnumerable instructions) { MethodInfo original = AccessTools.DeclaredMethod(typeof(AppDomain), "GetAssemblies", Type.EmptyTypes, (Type[])null); MethodInfo ours = AccessTools.DeclaredMethod(typeof(InteropTypeSweep), "Mortals", new Type[1] { typeof(AppDomain) }, (Type[])null); foreach (CodeInstruction instruction in instructions) { if (original != null && ours != null && CodeInstructionExtensions.Calls(instruction, original)) { _replaced++; yield return CodeInstructionExtensions.WithBlocks(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Call, (object)ours), (IEnumerable