-
Notifications
You must be signed in to change notification settings - Fork 800
v7: Redesign the plugin loading api to a phase model #999
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
aldelaro5
wants to merge
9
commits into
BepInEx:v7-dev
Choose a base branch
from
aldelaro5:api-refactor-v2
base: v7-dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
4740cb2
Refine access modifiers and xmldoc
aldelaro5 c0b67d6
Move BepInExVersion to Utility
aldelaro5 66dd61a
Remove obsoleted members from the config api
aldelaro5 72ba0fc
Refactor the entire plugin loading and metadata api
aldelaro5 ab2cab9
Change the write unity disk logging default setting to true
aldelaro5 b27dedd
Redesign the plugin loading API to a phase model
aldelaro5 b06d68a
Move func into delegate types
aldelaro5 dc666af
Remove the redundant phase suffix in phases names
aldelaro5 911c267
Clarify the phase check in the default plugin provider
aldelaro5 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| using System; | ||
| using System.IO; | ||
| using System.Linq; | ||
| using System.Reflection; | ||
| using System.Text; | ||
| using BepInEx.Configuration; | ||
| using BepInEx.Core.Bootstrap; | ||
| using BepInEx.Logging; | ||
|
|
||
| namespace BepInEx; | ||
|
|
||
| /// <summary> | ||
| /// The base type of any chainloaders no matter the runtime | ||
| /// </summary> | ||
| public abstract class Chainloader | ||
| { | ||
| private static readonly ConfigEntry<bool> ConfigDiskAppend = ConfigFile.CoreConfig.Bind( | ||
| "Logging.Disk", "AppendLog", | ||
| false, | ||
| "Appends to the log file instead of overwriting, on game startup."); | ||
|
|
||
| private static readonly ConfigEntry<bool> ConfigDiskLogging = ConfigFile.CoreConfig.Bind( | ||
| "Logging.Disk", "Enabled", | ||
| true, | ||
| "Enables writing log messages to disk."); | ||
|
|
||
| private static readonly ConfigEntry<LogLevel> ConfigDiskLoggingDisplayedLevel = ConfigFile.CoreConfig.Bind( | ||
| "Logging.Disk", "LogLevels", | ||
| LogLevel.Fatal | LogLevel.Error | LogLevel.Warning | LogLevel.Message | LogLevel.Info, | ||
| "Only displays the specified log levels in the disk log output."); | ||
|
|
||
| private static readonly ConfigEntry<bool> ConfigDiskLoggingInstantFlushing = ConfigFile.CoreConfig.Bind( | ||
| "Logging.Disk", "InstantFlushing", | ||
| false, | ||
| new StringBuilder() | ||
| .AppendLine("If true, instantly writes any received log entries to disk.") | ||
| .AppendLine("This incurs a major performance hit if a lot of log messages are being written, however it is really useful for debugging crashes.") | ||
| .ToString()); | ||
|
|
||
| private static readonly ConfigEntry<int> ConfigDiskLoggingFileLimit = ConfigFile.CoreConfig.Bind( | ||
| "Logging.Disk", "ConcurrentFileLimit", | ||
| 5, | ||
| new StringBuilder() | ||
| .AppendLine("The maximum amount of concurrent log files that will be written to disk.") | ||
| .AppendLine("As one log file is used per open game instance, you may find it necessary to increase this limit when debugging multiple instances at the same time.") | ||
| .ToString()); | ||
|
|
||
| internal Chainloader() { } | ||
|
|
||
| /// <summary> | ||
| /// The title of the console | ||
| /// </summary> | ||
| private string ConsoleTitle => $"BepInEx {Utility.BepInExVersion} - {Paths.ProcessName}"; | ||
|
|
||
| /// <summary> | ||
| /// Whether the loading system was initialised | ||
| /// </summary> | ||
| private bool Initialized { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The current chainloader instance | ||
| /// </summary> | ||
| protected static Chainloader Instance { get; set; } | ||
|
|
||
| internal virtual void Initialize(string gameExePath = null) | ||
| { | ||
| if (Initialized) | ||
| throw new InvalidOperationException("Chainloader cannot be initialized multiple times"); | ||
|
|
||
| Instance = this; | ||
|
|
||
| // Set vitals | ||
| if (gameExePath != null) | ||
| // Checking for null allows a more advanced initialization workflow, where the Paths class has been initialized before calling Chainloader.Initialize | ||
| // This is used by Preloader to use environment variables, for example | ||
| Paths.SetExecutablePath(gameExePath); | ||
|
|
||
| InitializeLoggers(); | ||
|
|
||
| if (!Directory.Exists(Paths.PluginPath)) | ||
| Directory.CreateDirectory(Paths.PluginPath); | ||
|
|
||
| Initialized = true; | ||
|
|
||
| Logger.Log(LogLevel.Message, "Chainloader initialized"); | ||
| } | ||
|
|
||
| internal virtual void InitializeLoggers() | ||
| { | ||
| if (ConsoleManager.ConsoleEnabled && !ConsoleManager.ConsoleActive) | ||
| ConsoleManager.CreateConsole(); | ||
|
|
||
| if (ConsoleManager.ConsoleActive) | ||
| { | ||
| if (!Logger.Listeners.Any(x => x is ConsoleLogListener)) | ||
| Logger.Listeners.Add(new ConsoleLogListener()); | ||
|
|
||
| ConsoleManager.SetConsoleTitle(ConsoleTitle); | ||
| } | ||
|
|
||
| if (ConfigDiskLogging.Value) | ||
| Logger.Listeners.Add(new DiskLogListener("LogOutput.log", ConfigDiskLoggingDisplayedLevel.Value, | ||
| ConfigDiskAppend.Value, ConfigDiskLoggingInstantFlushing.Value, | ||
| ConfigDiskLoggingFileLimit.Value)); | ||
|
|
||
| if (!TraceLogSource.IsListening) | ||
| Logger.Sources.Add(TraceLogSource.CreateSource()); | ||
|
|
||
| if (!Logger.Sources.Any(x => x is HarmonyLogSource)) | ||
| Logger.Sources.Add(new HarmonyLogSource()); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| using System; | ||
| using BepInEx.Logging; | ||
|
|
||
| namespace BepInEx.Core.Bootstrap; | ||
|
|
||
| /// <summary> | ||
| /// The manager class that allows to start phases and to listen when a phase starts | ||
| /// </summary> | ||
| public class PhaseManager | ||
| { | ||
| /// <summary> | ||
| /// The current instance of the phase manager | ||
| /// </summary> | ||
| public static PhaseManager Instance { get; } = new(); | ||
|
|
||
| private PhaseManager() { } | ||
|
|
||
| /// <summary> | ||
| /// The current phase | ||
| /// </summary> | ||
| public string CurrentPhase { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// Occurs when a phase starts | ||
| /// </summary> | ||
| public event Action<string> OnPhaseStarted; | ||
|
|
||
| /// <summary> | ||
| /// Starts a phase | ||
| /// </summary> | ||
| /// <param name="phase">The name of the phase</param> | ||
| /// <seealso cref="BepInPhases"/> | ||
| public void StartPhase(string phase) | ||
| { | ||
| Logger.Log(LogLevel.Message, "Started phase " + phase); | ||
| CurrentPhase = phase; | ||
| OnPhaseStarted?.Invoke(phase); | ||
| Logger.Log(LogLevel.Message, "Ended phase " + phase); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logging overall seems pretty excessive or at least at wrong levels. Something to look into later once things are getting finalized. This seems like a good place to add a StopWatch and log how long a phase took. |
||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| using System; | ||
| using System.Reflection; | ||
|
|
||
| namespace BepInEx.Core.Bootstrap; | ||
|
|
||
| /// <summary> | ||
| /// Info about the loading of a plugin | ||
| /// </summary> | ||
| public class PluginLoadEventArgs : EventArgs | ||
| { | ||
| /// <summary> | ||
| /// The concerned plugin | ||
| /// </summary> | ||
| public PluginInfo PluginInfo { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// The plugin's assembly | ||
| /// </summary> | ||
| public Assembly Assembly { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// The plugin's instance | ||
| /// </summary> | ||
| public Plugin PluginInstance { get; internal set; } | ||
|
|
||
| internal PluginLoadEventArgs(PluginInfo pluginInfo, Assembly assembly, Plugin pluginInstance) | ||
| { | ||
| PluginInfo = pluginInfo; | ||
| Assembly = assembly; | ||
| PluginInstance = pluginInstance; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about caching all of these contexts (as cached contexts) instead of reiterating over the files on every phase? Or do we expect dll files to be dropped at runtime? Wouldn't this add up across different providers having to reload on every phase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a discussion item in the OP because it depends if we expect the discovery to not change at entrypoint time