feat(plugins): complete Campaign LA5 cross-host hosting

This commit is contained in:
Erik 2026-08-14 18:12:59 +02:00
parent 6c4cd2bbc6
commit 95f4be94db
26 changed files with 1630 additions and 99 deletions

View file

@ -7,6 +7,14 @@ namespace AcDream.Plugin.Abstractions;
/// </summary>
public interface IPluginHost
{
/// <summary>
/// <see langword="true"/> when <see cref="Ui"/> registrations can be
/// projected by this host. No-window hosts return <see langword="false"/>
/// and expose <see cref="NoOpUiRegistry.Instance"/> so a plugin may keep
/// one code path while deliberately omitting presentation work.
/// </summary>
bool HasUi { get; }
IPluginLogger Log { get; }
IGameState State { get; }
IEvents Events { get; }

View file

@ -3,8 +3,10 @@ namespace AcDream.Plugin.Abstractions;
/// <summary>
/// Plugin-facing UI registration. A plugin ships a markup file (KSML-style) +
/// a binding object exposing the data properties the markup binds to, and
/// registers it from <c>Enable()</c>. Calls made before the GL window opens are
/// buffered and drained once the UI host exists.
/// registers it from <c>Enable()</c>. Graphical hosts buffer registrations until
/// their retained UI exists. A host whose <see cref="IPluginHost.HasUi"/> is
/// <see langword="false"/> exposes <see cref="NoOpUiRegistry.Instance"/> and
/// intentionally discards registrations.
/// </summary>
public interface IUiRegistry
{
@ -12,3 +14,21 @@ public interface IUiRegistry
/// <param name="binding">Object whose properties the markup's {Bindings} resolve against.</param>
void AddMarkupPanel(string markupPath, object binding);
}
/// <summary>
/// BCL-only UI sink for no-window plugin hosts. It intentionally retains
/// neither markup paths nor binding objects, so a UI registration cannot keep
/// a plugin assembly alive after its collectible load context is unloaded.
/// </summary>
public sealed class NoOpUiRegistry : IUiRegistry
{
public static NoOpUiRegistry Instance { get; } = new();
private NoOpUiRegistry()
{
}
public void AddMarkupPanel(string markupPath, object binding)
{
}
}