/// <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);
                }
            }
        }
Beispiel #3
0
        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;
            }
        }
Beispiel #5
0
 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.");
        }
Beispiel #10
0
        /// <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);
            }
        }
Beispiel #11
0
		static string GetKeyName(MethodPatcher method, bool original) => $"{method.FriendlyName}{(original ? orgPrfx : edtdPrfx)}";
Beispiel #12
0
		public static void StoreMethod(MethodPatcher method, bool original)
		{
			if (MainClass.gendiffs)
				instance.Add(TABLE, GetKeyName(method, original), method.methodDefinition.PrintCSharp());
		}
Beispiel #13
0
		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();
		}
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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);
        }