/// <summary>Called when this mod is enabled.</summary> public void OnEnabled() { if (!isWorkshopMode) { Log.Info($"The 'More Vehicles' mod version {modVersion} cannot be started because of no Steam Workshop"); return; } if (Compatibility.AreAnyIncompatibleModsActive()) { Log.Info($"The 'More Vehicles' mod version {modVersion} cannot be started because of incompatible mods"); return; } Log.Info("The 'More Vehicles' mod has been enabled, version: " + modVersion); patcher = new MethodPatcher(HarmonyId, patches); var patchedMethods = patcher.Apply(); if (patchedMethods.Count == patches.Length) { PluginManager.instance.eventPluginsChanged += ModsChanged; VehicleManagerCustomizer.Customize(); } else { Log.Error("The 'More Vehicles' mod failed to perform method redirections"); patcher.Revert(); patcher = null; } }
public void Test_CanGetInstructionsWithNoILGenerator() { var method = typeof(Class12).GetMethod(nameof(Class12.FizzBuzz)); var instrsNoGen = MethodBodyReader.GetInstructions(generator: null, method); var dynamicMethod = MethodPatcher.CreateDynamicMethod(method, "_Patch", false); var instrsHasGen = MethodBodyReader.GetInstructions(dynamicMethod.GetILGenerator(), method); Assert.AreEqual(instrsNoGen.Count, instrsHasGen.Count); for (var i = 0; i < instrsNoGen.Count; i++) { var instrNoGen = instrsNoGen[i]; var instrHasGen = instrsHasGen[i]; Assert.AreEqual(instrNoGen.offset, instrHasGen.offset, "offset @ {0} ({1})", i, instrNoGen); Assert.AreEqual(instrNoGen.opcode, instrHasGen.opcode, "opcode @ {0} ({1})", i, instrNoGen); AssertAreEqual(instrNoGen.operand, instrHasGen.operand, "operand", i, instrNoGen); CollectionAssert.AreEqual(instrNoGen.labels, instrHasGen.labels, "labels @ {0}", i); CollectionAssert.AreEqual(instrNoGen.blocks, instrHasGen.blocks, "blocks @ {0}", i); AssertAreEqual(instrNoGen.argument, instrHasGen.argument, "argument", i, instrNoGen); // The only difference between w/o gen and w/ gen is this: var operandType = instrNoGen.opcode.OperandType; if ((operandType == OperandType.ShortInlineVar || operandType == OperandType.InlineVar) && instrNoGen.argument is object) { #if NETCOREAPP3_0 || NETCOREAPP3_1 Assert.AreEqual("System.Reflection.RuntimeLocalVariableInfo", instrNoGen.argument.GetType().FullName, "w/o generator argument type @ {0} ({1})", i, instrNoGen); #else Assert.AreEqual("System.Reflection.LocalVariableInfo", instrNoGen.argument.GetType().FullName, "w/o generator argument type @ {0} ({1})", i, instrNoGen); #endif Assert.AreEqual(typeof(LocalBuilder), instrHasGen.argument.GetType(), "w/ generator argument type @ {0} ({1})", i, instrNoGen); } } }
public static MethodInfo UpdateWrapper(MethodBase original, ILGenerator il) { PatchProcessor patchProcessor = RimThreadedHarmony.harmony.CreateProcessor(original); PatchInfo patchInfo = HarmonySharedState.GetPatchInfo(patchProcessor.original) ?? new PatchInfo(); bool debug = patchInfo.Debugging || Harmony.DEBUG; List <MethodInfo> sortedPatchMethods = PatchFunctions.GetSortedPatchMethods(original, patchInfo.prefixes, debug); List <MethodInfo> sortedPatchMethods2 = PatchFunctions.GetSortedPatchMethods(original, patchInfo.postfixes, debug); List <MethodInfo> sortedPatchMethods3 = PatchFunctions.GetSortedPatchMethods(original, patchInfo.transpilers, debug); List <MethodInfo> sortedPatchMethods4 = PatchFunctions.GetSortedPatchMethods(original, patchInfo.finalizers, debug); Dictionary <int, CodeInstruction> finalInstructions; MethodPatcher methodPatcher = new MethodPatcher(original, null, sortedPatchMethods, sortedPatchMethods2, sortedPatchMethods3, sortedPatchMethods4, debug); methodPatcher.il = il; MethodInfo methodInfo = methodPatcher.CreateReplacement(out finalInstructions); if (methodInfo == null) { throw new MissingMethodException("Cannot create replacement for " + original.FullDescription()); } try { Memory.DetourMethodAndPersist(original, methodInfo); } finally { } return(methodInfo); }
/// <summary> /// Performs mod registration when a game level is unloaded. /// </summary> public override void OnLevelUnloading() { base.OnLevelUnloading(); if (patcher == null) { return; } switch (currentloadmode) { case LoadMode.NewGame: case LoadMode.LoadGame: case LoadMode.LoadScenario: case LoadMode.NewGameFromScenario: break; default: var patchedMethods = patcher.Apply(); if (patchedMethods.Count == patches.Length) { PluginManager.instance.eventPluginsChanged += ModsChanged; VehicleManagerCustomizer.Customize(); } else { Log.Error("The 'More Vehicles' mod failed to perform method redirections"); patcher.Revert(); patcher = null; } return; } }
private RealTimeCore(TimeAdjustment timeAdjustment, CustomTimeBar timeBar, RealTimeEventManager eventManager, MethodPatcher patcher) { this.timeAdjustment = timeAdjustment; this.timeBar = timeBar; this.eventManager = eventManager; this.patcher = patcher; isEnabled = true; }
private static void SafeRevertPatches(MethodPatcher patcher) { try { patcher.Revert(); } catch (Exception ex) { Log.Warning("The 'Real Time' mod failed to revert method redirections: " + ex); } }
/// <summary> /// Performs mod registration when a game level is loaded. /// </summary> /// <param name="mode">The mode the game level is loaded in.</param> public override void OnLevelLoaded(LoadMode mode) { currentloadmode = mode; if (patcher == null) { return; } switch (mode) { case LoadMode.NewGame: case LoadMode.LoadGame: case LoadMode.LoadScenario: case LoadMode.NewGameFromScenario: break; default: if (!isWorkshopMode || patcher == null) { return; } PluginManager.instance.eventPluginsChanged -= ModsChanged; patcher.Revert(); patcher = null; VehicleManagerCustomizer.Revert(); Log.Info("The 'More Vehicles' mod has been disabled in Map or Asset editor mod"); return; } var gameMetadata = SimulationManager.instance.m_metaData; if (gameMetadata == null) { return; } lock (gameMetadata) { if (gameMetadata.m_modOverride == null) { gameMetadata.m_modOverride = new Dictionary <string, bool>(); } gameMetadata.m_modOverride[Constants.MetadataModName] = true; } }
/// <summary>Called when this mod is enabled.</summary> public void OnEnabled() { Log.SetupDebug(Name); if (!isWorkshopMode) { Log.Info($"The 'More Vehicles' mod version {modVersion} cannot be started because of no Steam Workshop"); return; } if (Compatibility.AreAnyIncompatibleModsActive()) { Log.Info($"The 'More Vehicles' mod version {modVersion} cannot be started because of incompatible mods"); return; } Log.Info("The 'More Vehicles' mod has been enabled, version: " + modVersion); IPatch[] patches = { CinematicCameraControllerPatch.GetNearestVehicle, CinematicCameraControllerPatch.GetRandomVehicle, CinematicCameraControllerPatch.GetVehicleWithName, OutsideConnectionAIPatch.DummyTrafficProbability, PathVisualizerPatch.AddPathsImpl, ResidentAIPatch.DoRandomMove, TouristAIPatch.DoRandomMove, VehicleManagerPatch.DataDeserialize, VehicleManagerPatch.SimulationStepImpl, VehicleManagerPatch.UpdateData, VehiclePatch.GetTargetFrame, }; patcher = new MethodPatcher(HarmonyId, patches); var patchedMethods = patcher.Apply(); if (patchedMethods.Count == patches.Length) { PluginManager.instance.eventPluginsChanged += ModsChanged; VehicleManagerCustomizer.Customize(); } else { Log.Error("The 'More Vehicles' mod failed to perform method redirections"); patcher.Revert(); patcher = null; } }
/// <summary>Called when this mod is disabled.</summary> public void OnDisabled() { if (!isWorkshopMode || patcher == null) { return; } PluginManager.instance.eventPluginsChanged -= ModsChanged; patcher.Revert(); patcher = null; VehicleManagerCustomizer.Revert(); Log.Info("The 'More Vehicles' mod has been disabled."); }
/// <summary>Starts the benchmarking by applying the corresponding method patches.</summary> /// <returns><c>true</c> on success, <c>false</c> on failure.</returns> public bool Start() { BenchmarkPatch.DataCollector.Clear(); patcher = new MethodPatcher(HarmonyId, patches); try { patcher.Apply(); isRunning = true; return(true); } catch (Exception ex) { Log.Error("Failed to start benchmarking: " + ex); return(false); } }
static string GetKeyName(MethodPatcher method, bool original) => $"{method.FriendlyName}{(original ? orgPrfx : edtdPrfx)}";
public static void StoreMethod(MethodPatcher method, bool original) { if (MainClass.gendiffs) instance.Add(TABLE, GetKeyName(method, original), method.methodDefinition.PrintCSharp()); }
public static bool CheckMethod(MethodPatcher method, bool original) { if (TABLE == 1) return true; return (string)instance.Get(TABLE - 1, GetKeyName(method, original)) == method.methodDefinition.PrintCSharp(); }
public static RealTimeCore Run( ConfigurationProvider <RealTimeConfig> configProvider, string rootPath, ILocalizationProvider localizationProvider, bool setDefaultTime, Compatibility compatibility) { if (configProvider == null) { throw new ArgumentNullException(nameof(configProvider)); } if (string.IsNullOrEmpty(rootPath)) { throw new ArgumentException("The root path cannot be null or empty string", nameof(rootPath)); } if (localizationProvider == null) { throw new ArgumentNullException(nameof(localizationProvider)); } if (compatibility == null) { throw new ArgumentNullException(nameof(compatibility)); } var patches = GetMethodPatches(compatibility); var patcher = new MethodPatcher(HarmonyId, patches); var appliedPatches = patcher.Apply(); if (!CheckRequiredMethodPatches(appliedPatches)) { Log.Error("The 'Real Time' mod failed to perform method redirections for required methods"); patcher.Revert(); return(null); } if (StorageBase.CurrentLevelStorage != null) { LoadStorageData(new[] { configProvider }, StorageBase.CurrentLevelStorage); } localizationProvider.SetEnglishUSFormatsState(configProvider.Configuration.UseEnglishUSFormats); var timeInfo = new TimeInfo(configProvider.Configuration); var buildingManager = new BuildingManagerConnection(); var randomizer = new GameRandomizer(); var weatherInfo = new WeatherInfo(new WeatherManagerConnection(), randomizer); var gameConnections = new GameConnections <Citizen>( timeInfo, new CitizenConnection(), new CitizenManagerConnection(), buildingManager, randomizer, new TransferManagerConnection(), weatherInfo); var eventManager = new RealTimeEventManager( configProvider.Configuration, CityEventsLoader.Instance, new EventManagerConnection(), buildingManager, randomizer, timeInfo, Constants.MaxTravelTime); if (!SetupCustomAI(timeInfo, configProvider.Configuration, gameConnections, eventManager, compatibility)) { Log.Error("The 'Real Time' mod failed to setup the customized AI and will now be deactivated."); patcher.Revert(); return(null); } var timeAdjustment = new TimeAdjustment(configProvider.Configuration); var gameDate = timeAdjustment.Enable(setDefaultTime); SimulationHandler.CitizenProcessor.UpdateFrameDuration(); CityEventsLoader.Instance.ReloadEvents(rootPath); var customTimeBar = new CustomTimeBar(); customTimeBar.Enable(gameDate); customTimeBar.CityEventClick += CustomTimeBarCityEventClick; var vanillaEvents = VanillaEvents.Customize(); var result = new RealTimeCore(timeAdjustment, customTimeBar, eventManager, patcher, vanillaEvents); eventManager.EventsChanged += result.CityEventsChanged; var statistics = new Statistics(timeInfo, localizationProvider); if (statistics.Initialize()) { statistics.RefreshUnits(); } else { statistics = null; } SimulationHandler.NewDay += result.CityEventsChanged; SimulationHandler.TimeAdjustment = timeAdjustment; SimulationHandler.DayTimeSimulation = new DayTimeSimulation(configProvider.Configuration); SimulationHandler.EventManager = eventManager; SimulationHandler.WeatherInfo = weatherInfo; SimulationHandler.Buildings = BuildingAIPatch.RealTimeAI; SimulationHandler.Buildings.UpdateFrameDuration(); if (appliedPatches.Contains(CitizenManagerPatch.CreateCitizenPatch1)) { CitizenManagerPatch.NewCitizenBehavior = new NewCitizenBehavior(randomizer, configProvider.Configuration); } if (appliedPatches.Contains(BuildingAIPatch.GetColor)) { SimulationHandler.Buildings.InitializeLightState(); } SimulationHandler.Statistics = statistics; if (appliedPatches.Contains(WorldInfoPanelPatch.UpdateBindings)) { WorldInfoPanelPatch.CitizenInfoPanel = CustomCitizenInfoPanel.Enable(ResidentAIPatch.RealTimeAI, localizationProvider); WorldInfoPanelPatch.VehicleInfoPanel = CustomVehicleInfoPanel.Enable(ResidentAIPatch.RealTimeAI, localizationProvider); WorldInfoPanelPatch.CampusWorldInfoPanel = CustomCampusWorldInfoPanel.Enable(localizationProvider); } AwakeSleepSimulation.Install(configProvider.Configuration); var schedulesStorage = ResidentAIPatch.RealTimeAI.GetStorageService( schedules => new CitizenScheduleStorage(schedules, gameConnections.CitizenManager.GetCitizensArray, timeInfo)); result.storageData.Add(schedulesStorage); result.storageData.Add(eventManager); if (StorageBase.CurrentLevelStorage != null) { StorageBase.CurrentLevelStorage.GameSaving += result.GameSaving; LoadStorageData(result.storageData, StorageBase.CurrentLevelStorage); } result.storageData.Add(configProvider); result.Translate(localizationProvider); result.IsRestrictedMode = appliedPatches.Count != patches.Count; return(result); }
public static RealTimeCore Run(RealTimeConfig config, string rootPath, ILocalizationProvider localizationProvider) { if (config == null) { throw new ArgumentNullException(nameof(config)); } if (string.IsNullOrEmpty(rootPath)) { throw new ArgumentException("The root path cannot be null or empty string", nameof(rootPath)); } if (localizationProvider == null) { throw new ArgumentNullException(nameof(localizationProvider)); } var patcher = new MethodPatcher( BuildingAIPatches.PrivateConstructionTime, BuildingAIPatches.PrivateHandleWorkers, BuildingAIPatches.CommercialSimulation, ResidentAIPatch.Location, ResidentAIPatch.ArriveAtDestination, TouristAIPatch.Location, UIGraphPatches.MinDataPoints, UIGraphPatches.VisibleEndTime, UIGraphPatches.BuildLabels); try { patcher.Apply(); Log.Info("The 'Real Time' successfully performed the methods redirections"); } catch (Exception ex) { Log.Error("The 'Real Time' mod failed to perform method redirections: " + ex); patcher.Revert(); return(null); } var timeInfo = new TimeInfo(config); var buildingManager = new BuildingManagerConnection(); var randomizer = new GameRandomizer(); var weatherInfo = new WeatherInfo(new WeatherManagerConnection()); var gameConnections = new GameConnections <Citizen>( timeInfo, new CitizenConnection(), new CitizenManagerConnection(), buildingManager, randomizer, new TransferManagerConnection(), weatherInfo); var eventManager = new RealTimeEventManager( config, CityEventsLoader.Instance, new EventManagerConnection(), buildingManager, randomizer, timeInfo); if (!SetupCustomAI(timeInfo, config, gameConnections, eventManager)) { Log.Error("The 'Real Time' mod failed to setup the customized AI and will now be deactivated."); patcher.Revert(); return(null); } var timeAdjustment = new TimeAdjustment(config); DateTime gameDate = timeAdjustment.Enable(); SimulationHandler.CitizenProcessor.SetFrameDuration(timeAdjustment.HoursPerFrame); CityEventsLoader.Instance.ReloadEvents(rootPath); var customTimeBar = new CustomTimeBar(); customTimeBar.Enable(gameDate); customTimeBar.CityEventClick += CustomTimeBarCityEventClick; var result = new RealTimeCore(timeAdjustment, customTimeBar, eventManager, patcher); eventManager.EventsChanged += result.CityEventsChanged; SimulationHandler.NewDay += result.CityEventsChanged; SimulationHandler.TimeAdjustment = timeAdjustment; SimulationHandler.DayTimeSimulation = new DayTimeSimulation(config); SimulationHandler.EventManager = eventManager; SimulationHandler.WeatherInfo = weatherInfo; SimulationHandler.Buildings = BuildingAIPatches.RealTimeAI; AwakeSleepSimulation.Install(config); RealTimeStorage.CurrentLevelStorage.GameSaving += result.GameSaving; result.storageData.Add(eventManager); result.storageData.Add(ResidentAIPatch.RealTimeAI.GetStorageService()); result.LoadStorageData(); result.Translate(localizationProvider); return(result); }