From 8da105313e975c6f903b95171333cdca82f906f7 Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 25 Oct 2026 17:50:51 +0100 Subject: [PATCH] Improve event handling and the eventing API --- StarMap.API/Events/IEventPublisher.cs | 7 + StarMap.API/Events/ISubscription.cs | 6 + StarMap.API/Mediation/IEventPublisher.cs | 8 - StarMap.API/Mediation/IStarMapEvent.cs | 6 - StarMap.API/Mediation/ISubscription.cs | 6 - StarMap.API/Services/IEventBus.cs | 13 ++ StarMap.API/Services/IMediationService.cs | 10 -- StarMap.Core/API/EventBus.cs | 39 +++++ StarMap.Core/API/MediationService.cs | 29 ---- StarMap.Core/Services/Mediator.cs | 194 ++++++++++++---------- StarMap.Core/StarMapCore.cs | 2 +- docs/modding/constructor-injection.md | 3 +- docs/modding/dependencies.md | 4 +- docs/modding/event-bus.md | 109 ++++++++++++ docs/modding/event-mediation.md | 100 ----------- docs/modding/index.md | 2 +- docs/modding/lifecycle.md | 2 +- docs/modding/mod-services.md | 2 +- docs/modding/services.md | 2 +- mkdocs.yml | 2 +- 20 files changed, 285 insertions(+), 261 deletions(-) create mode 100644 StarMap.API/Events/IEventPublisher.cs create mode 100644 StarMap.API/Events/ISubscription.cs delete mode 100644 StarMap.API/Mediation/IEventPublisher.cs delete mode 100644 StarMap.API/Mediation/IStarMapEvent.cs delete mode 100644 StarMap.API/Mediation/ISubscription.cs create mode 100644 StarMap.API/Services/IEventBus.cs delete mode 100644 StarMap.API/Services/IMediationService.cs create mode 100644 StarMap.Core/API/EventBus.cs delete mode 100644 StarMap.Core/API/MediationService.cs create mode 100644 docs/modding/event-bus.md delete mode 100644 docs/modding/event-mediation.md diff --git a/StarMap.API/Events/IEventPublisher.cs b/StarMap.API/Events/IEventPublisher.cs new file mode 100644 index 0000000..8145171 --- /dev/null +++ b/StarMap.API/Events/IEventPublisher.cs @@ -0,0 +1,7 @@ +namespace StarMap.API.Events +{ + public interface IEventPublisher : IDisposable + { + void Publish(T message); + } +} diff --git a/StarMap.API/Events/ISubscription.cs b/StarMap.API/Events/ISubscription.cs new file mode 100644 index 0000000..45e277a --- /dev/null +++ b/StarMap.API/Events/ISubscription.cs @@ -0,0 +1,6 @@ +namespace StarMap.API.Events +{ + public interface ISubscription : IDisposable + { + } +} diff --git a/StarMap.API/Mediation/IEventPublisher.cs b/StarMap.API/Mediation/IEventPublisher.cs deleted file mode 100644 index 6a2f057..0000000 --- a/StarMap.API/Mediation/IEventPublisher.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace StarMap.API.Mediation -{ - public interface IEventPublisher : IDisposable where T : IStarMapEvent - { - void Publish(T message); - Task PublishParallel(T message); - } -} diff --git a/StarMap.API/Mediation/IStarMapEvent.cs b/StarMap.API/Mediation/IStarMapEvent.cs deleted file mode 100644 index fbbfbf5..0000000 --- a/StarMap.API/Mediation/IStarMapEvent.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace StarMap.API.Mediation -{ - public interface IStarMapEvent - { - } -} diff --git a/StarMap.API/Mediation/ISubscription.cs b/StarMap.API/Mediation/ISubscription.cs deleted file mode 100644 index 47f02d1..0000000 --- a/StarMap.API/Mediation/ISubscription.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace StarMap.API.Mediation -{ - public interface ISubscription : IDisposable where T : IStarMapEvent - { - } -} diff --git a/StarMap.API/Services/IEventBus.cs b/StarMap.API/Services/IEventBus.cs new file mode 100644 index 0000000..fa9432e --- /dev/null +++ b/StarMap.API/Services/IEventBus.cs @@ -0,0 +1,13 @@ +using StarMap.API.Events; + +namespace StarMap.API.Services +{ + public interface IEventBus + { + IEventPublisher GetPublisher(); + IEventPublisher GetPublisher(string eventName); + + ISubscription Subscribe(Action handler); + ISubscription Subscribe(Action handler, string eventName); + } +} diff --git a/StarMap.API/Services/IMediationService.cs b/StarMap.API/Services/IMediationService.cs deleted file mode 100644 index d8f3450..0000000 --- a/StarMap.API/Services/IMediationService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using StarMap.API.Mediation; - -namespace StarMap.API.Services -{ - public interface IMediationService - { - ISubscription Subscribe(Action handler) where T : IStarMapEvent; - IEventPublisher RegisterPublisher() where T : IStarMapEvent; - } -} diff --git a/StarMap.Core/API/EventBus.cs b/StarMap.Core/API/EventBus.cs new file mode 100644 index 0000000..a9373c2 --- /dev/null +++ b/StarMap.Core/API/EventBus.cs @@ -0,0 +1,39 @@ +using StarMap.API.Events; +using StarMap.API.Services; +using StarMap.Core.ModRepository; +using StarMap.Core.Services; + +namespace StarMap.Core.API +{ + internal class EventBus : IEventBus + { + private readonly RuntimeMod _mod; + private readonly IMediator _mediator; + + public EventBus(IModContext modContext, IMediator mediator) + { + _mod = modContext.Mod; + _mediator = mediator; + } + + public IEventPublisher GetPublisher() + { + return _mediator.GetPublisher(); + } + + public IEventPublisher GetPublisher(string eventName) + { + return _mediator.GetPublisher(eventName); + } + + public ISubscription Subscribe(Action handler) + { + return _mediator.Subscribe(handler); + } + + public ISubscription Subscribe(Action handler, string eventName) + { + return _mediator.Subscribe(handler, eventName); + } + } +} diff --git a/StarMap.Core/API/MediationService.cs b/StarMap.Core/API/MediationService.cs deleted file mode 100644 index 4767293..0000000 --- a/StarMap.Core/API/MediationService.cs +++ /dev/null @@ -1,29 +0,0 @@ -using StarMap.API.Mediation; -using StarMap.API.Services; -using StarMap.Core.ModRepository; -using StarMap.Core.Services; - -namespace StarMap.Core.API -{ - internal class MediationService : IMediationService - { - private readonly RuntimeMod _mod; - private readonly IMediator _mediator; - - public MediationService(IModContext modContext, IMediator mediator) - { - _mod = modContext.Mod; - _mediator = mediator; - } - - public IEventPublisher RegisterPublisher() where T : IStarMapEvent - { - return _mediator.RegisterPublisher(_mod); - } - - public ISubscription Subscribe(Action handler) where T : IStarMapEvent - { - return _mediator.Subscribe(handler); - } - } -} diff --git a/StarMap.Core/Services/Mediator.cs b/StarMap.Core/Services/Mediator.cs index b760c3c..97c6011 100644 --- a/StarMap.Core/Services/Mediator.cs +++ b/StarMap.Core/Services/Mediator.cs @@ -1,154 +1,164 @@ -using StarMap.API.Mediation; -using StarMap.Core.ModRepository; +using StarMap.API.Events; using System.Collections.Concurrent; -using System.Runtime.Loader; namespace StarMap.Core.Services { internal interface IMediator { - IEventPublisher RegisterPublisher(RuntimeMod mod) where T : IStarMapEvent; - ISubscription Subscribe(Action action) where T : IStarMapEvent; - } + IEventPublisher GetPublisher(); + IEventPublisher GetPublisher(string eventName); - public interface IEventPublisher { } + ISubscription Subscribe(Action handler); + ISubscription Subscribe(Action handler, string eventName); + } - internal class SubscriptionHandle : ISubscription where T : IStarMapEvent + internal class Mediator : IMediator { - private readonly EventPublisher _publisher; + private interface IEventBus { } - private readonly Action _action; + private readonly ConcurrentDictionary _busses = []; - public SubscriptionHandle(EventPublisher publisher, Action action) + private TypeEventBus GetTypeBus() { - _publisher = publisher; - _action = action; + var bus = _busses.GetOrAdd(typeof(T), _ => new TypeEventBus()); + + if (bus is TypeEventBus typeBus) + return typeBus; + + throw new InvalidOperationException("Something went wrong in bus management"); } - public void Invoke(T message) + public IEventPublisher GetPublisher() { - _action.Invoke(message); + return GetTypeBus().CreatePublisher(); } - public void Dispose() + public IEventPublisher GetPublisher(string eventName) { - _publisher.Unsubscribe(this); + return GetTypeBus().GetNamedBus(eventName).CreatePublisher(); } - } - internal class EventPublisher(Mediator mediator) : IEventPublisher, IEventPublisher where T : IStarMapEvent - { - private readonly Lock _lock = new(); - - private bool _isDisposed; - - private readonly HashSet> _handlers = []; - - public ISubscription Subscribe(Action action) + public ISubscription Subscribe(Action handler) { - var handle = new SubscriptionHandle(this, action); - - lock (_lock) - { - ObjectDisposedException.ThrowIf(_isDisposed, this); - _handlers.Add(handle); - } - - return handle; + return GetTypeBus().Subscribe(handler); } - public void Unsubscribe(SubscriptionHandle handle) + public ISubscription Subscribe(Action handler, string eventName) { - lock (_lock) - { - if (_isDisposed) - return; - - _handlers.Remove(handle); - } + return GetTypeBus().GetNamedBus(eventName).Subscribe(handler); } - public void Publish(T message) + private class TypeEventBus() : EventBus() { - foreach (var handler in GetHandlersSnapshot()) + private readonly ConcurrentDictionary> _namedBusses = []; + + public EventBus GetNamedBus(string eventName) { - handler.Invoke(message); + return _namedBusses.GetOrAdd(eventName, (_) => new NamedEventBus()); } } - public Task PublishParallel(T message) + private class NamedEventBus() : EventBus() { } + + private abstract class EventBus() : IEventBus { - var tasks = new List(); + private readonly Lock _lock = new(); + - foreach (var handler in GetHandlersSnapshot()) + private HashSet> _subscription = []; + private HashSet> _publishers = []; + + public IEventPublisher CreatePublisher() { - tasks.Add(Task.Run(() => handler.Invoke(message))); + lock (_lock) + { + var publisher = new Publisher(this); + _publishers.Add(publisher); + return publisher; + } } - return Task.WhenAll(tasks); - } + public void RemovePublisher(IEventPublisher publisher) + { + lock (_lock) + { + _publishers.Remove(publisher); + } + } - private SubscriptionHandle[] GetHandlersSnapshot() - { - lock (_lock) + public ISubscription Subscribe(Action action) { - if (_isDisposed) - return []; + lock (_lock) + { + var subHandle = new SubscriptionHandle(this, action); + _subscription.Add(subHandle); + return subHandle; + } + } - return [.. _handlers]; + public void Unsubscribe(SubscriptionHandle handle) + { + lock (_lock) + { + _subscription.Remove(handle); + } } - } - public void Dispose() - { - lock (_lock) + public void Publish(T message) { - if (_isDisposed) - return; + SubscriptionHandle[] subscriptions; - _isDisposed = true; + lock (_lock) + { + subscriptions = [.. _subscription]; + } - mediator.UnregisterPublisher(this); - _handlers.Clear(); + foreach (var sub in subscriptions) + { + sub.Invoke(message); + } } - } - } - - internal class Mediator : IMediator - { - private readonly ConcurrentDictionary _publishers = []; - public IEventPublisher RegisterPublisher(RuntimeMod mod) where T : IStarMapEvent + private class Publisher(EventBus bus) : IEventPublisher { - var type = typeof(T); - if (AssemblyLoadContext.GetLoadContext(typeof(T).Assembly) != mod.ModAssemblyLoadContext) - throw new Exception("Events are only allowed to be published by the owner of the event type"); + private bool _isDisposed; - var publisher = new EventPublisher(this); + public void Publish(T message) + { + ObjectDisposedException.ThrowIf(Volatile.Read(ref _isDisposed), this); + bus.Publish(message); + } - if (!_publishers.TryAdd(type, publisher)) - throw new Exception($"A publisher for type '{typeof(T)}' was already registered"); + public void Dispose() + { + if (Interlocked.Exchange(ref _isDisposed, true)) + return; - return publisher; + bus.RemovePublisher(this); + } } - public void UnregisterPublisher(IEventPublisher publisher) + private class SubscriptionHandle : ISubscription { - _publishers.TryRemove(new(typeof(T), publisher)); - } + private readonly EventBus _bus; + private readonly Action _action; - public ISubscription Subscribe(Action action) where T : IStarMapEvent - { - if (!_publishers.TryGetValue(typeof(T), out var publisher)) + public SubscriptionHandle(EventBus bus, Action action) { - throw new Exception("A publisher for this event was not found"); + _bus = bus; + _action = action; } - if (publisher is not EventPublisher typedPublisher) - throw new Exception("Something went wrong in the type of the publisher"); + public void Invoke(T message) + { + _action.Invoke(message); + } - return typedPublisher.Subscribe(action); + public void Dispose() + { + _bus.Unsubscribe(this); + } } } } diff --git a/StarMap.Core/StarMapCore.cs b/StarMap.Core/StarMapCore.cs index 45d6855..573dc6d 100644 --- a/StarMap.Core/StarMapCore.cs +++ b/StarMap.Core/StarMapCore.cs @@ -29,7 +29,7 @@ public StarMapCore(AssemblyLoadContext coreAssemblyLoadContext) serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddSingleton(); diff --git a/docs/modding/constructor-injection.md b/docs/modding/constructor-injection.md index e24e43c..6bea8ac 100644 --- a/docs/modding/constructor-injection.md +++ b/docs/modding/constructor-injection.md @@ -6,7 +6,7 @@ The services currently registered in that scope are: - `IModServiceRegistry` for registering and retrieving services shared between mods - `IModMenuService` for adding items to KSA's **Mods** menu -- `IMediationService` for publishing and subscribing to typed events +- `IEventBus` for publishing and subscribing to typed messages - `IPatchService` for registering method patches ## Request services @@ -34,4 +34,3 @@ Use one public constructor, and ensure its parameters can be resolved from the s Constructor injection applies only to the `[StarMapMod]` entry class. Lifecycle callbacks are called with their documented fixed signatures; StarMap does not inject their parameters. See [lifecycle callbacks](lifecycle.md). Each mod has its own dependency-injection scope. Keep injected services on the entry class instance, and dispose handles returned by services, such as menu items, event publishers, and event subscriptions, in `[StarMapUnload]`. For cross-mod service contracts and registration, see [mod-provided services](mod-services.md). - diff --git a/docs/modding/dependencies.md b/docs/modding/dependencies.md index d422c9a..ea5bde5 100644 --- a/docs/modding/dependencies.md +++ b/docs/modding/dependencies.md @@ -42,9 +42,9 @@ StarMap loads each mod in a separate assembly load context. Declare inter-mod re ## Sharing event types between mods -When using [`IMediationService`](event-mediation.md), the event type must be defined in an assembly loaded by the publishing mod and shared with each subscribing mod. Add that assembly to the provider's `ExportedAssemblies` and to the consumer's `ImportedAssemblies`; make the provider a required dependency if the consumer subscribes during startup. +When using the [typed event bus](event-bus.md), every mod publishing or subscribing to a cross-mod message must use the same runtime type from a shared assembly. Add the contract assembly to the provider's `ExportedAssemblies` and to each dependent mod's `ImportedAssemblies`. Declare the provider as a dependency when its contract assembly is needed, and make it required if the mod cannot function without that assembly. A subscription does not require a publisher to be created first. -The consumer also needs a compile-time reference to the provider's event contract assembly. See [typed event mediation](event-mediation.md) for publisher and subscriber examples. +Each participating mod also needs a compile-time reference to the contract assembly. See the [typed event bus guide](event-bus.md) for publisher and subscriber examples. ## Sharing mod service contracts diff --git a/docs/modding/event-bus.md b/docs/modding/event-bus.md new file mode 100644 index 0000000..4c6aa88 --- /dev/null +++ b/docs/modding/event-bus.md @@ -0,0 +1,109 @@ +# Typed event bus + +`IEventBus` lets mods publish and subscribe to typed messages. The bus matches messages by their type; no marker interface is required: + +```csharp +public sealed record SelectionChanged(string Selection); +``` + +## Publishing a message + +Inject `IEventBus` into the `[StarMapMod]` entry class and get a publisher for the message type: + +```csharp +using StarMap.API; +using StarMap.API.Events; +using StarMap.API.Services; + +[StarMapMod] +public sealed class SelectionPublisher +{ + private readonly IEventBus _events; + private IEventPublisher? _publisher; + + public SelectionPublisher(IEventBus events) + { + _events = events; + } + + [StarMapBeforeMain] + public void Initialize() + { + _publisher = _events.GetPublisher(); + } + + public void ChangeSelection(string selection) + { + _publisher?.Publish(new SelectionChanged(selection)); + } + + [StarMapUnload] + public void Unload() + { + _publisher?.Dispose(); + } +} +``` + +## Subscribing to a message + +Subscribe with the same message type. A subscription can be created before any publisher: + +```csharp +using System; +using StarMap.API; +using StarMap.API.Events; +using StarMap.API.Services; + +[StarMapMod] +public sealed class SelectionSubscriber +{ + private readonly IEventBus _events; + private ISubscription? _subscription; + + public SelectionSubscriber(IEventBus events) + { + _events = events; + } + + [StarMapBeforeMain] + public void Initialize() + { + _subscription = _events.Subscribe(OnSelectionChanged); + } + + private void OnSelectionChanged(SelectionChanged message) + { + Console.WriteLine($"Selection changed to {message.Selection}"); + } + + [StarMapUnload] + public void Unload() + { + _subscription?.Dispose(); + } +} +``` + +Keep and dispose publisher and subscription handles when they are no longer needed, usually in `[StarMapUnload]`. Calling `Publish` on a disposed publisher throws `ObjectDisposedException`. The bus does not queue or replay messages sent before a subscription is added. + +## Named channels + +The overloads with an `eventName` string create a separate channel for that message type. The publisher and subscribers must use the same type and name: + +```csharp +_publisher = _events.GetPublisher("selection-panel"); +_subscription = _events.Subscribe( + OnSelectionChanged, + "selection-panel"); +``` + +Named channels are scoped to the message type; the same name used with a different type is a different channel. Calls without an event name use the default channel and do not communicate with named channels. + +## Message delivery + +`Publish` invokes the current subscribers synchronously on the calling thread. Handlers for one publish call run one at a time, but their order is not guaranteed. There is no parallel-publish or worker-thread dispatch API. A handler exception propagates from `Publish` and stops delivery for that call. Concurrent publish calls can invoke the same handler concurrently, so protect shared state as needed. + +## Sharing message types between mods + +Every mod publishing or subscribing to a cross-mod message must use the same runtime type from a shared assembly. Put message contracts in an assembly exported by the mod that provides them and imported by every other mod that uses those types. Each mod using the messages also needs a compile-time reference to the contract assembly. See [mod dependencies](dependencies.md#sharing-event-types-between-mods) for the configuration example. diff --git a/docs/modding/event-mediation.md b/docs/modding/event-mediation.md deleted file mode 100644 index 192a623..0000000 --- a/docs/modding/event-mediation.md +++ /dev/null @@ -1,100 +0,0 @@ -# Typed event mediation - -`IMediationService` lets mods publish and subscribe to typed events. Event types implement `IStarMapEvent`. Define an event type in an assembly loaded by the publishing mod: - -```csharp -using StarMap.API.Mediation; - -public sealed record SelectionChanged(string Selection) : IStarMapEvent; -``` - -## Publishing an event - -The mod that owns the event type registers its publisher once, then publishes messages: - -```csharp -using StarMap.API; -using StarMap.API.Mediation; -using StarMap.API.Services; - -[StarMapMod] -public sealed class SelectionPublisher -{ - private readonly IMediationService _events; - private IEventPublisher? _publisher; - - public SelectionPublisher(IMediationService events) - { - _events = events; - } - - [StarMapBeforeMain] - public void Initialize() - { - _publisher = _events.RegisterPublisher(); - } - - public void ChangeSelection(string selection) - { - _publisher?.Publish(new SelectionChanged(selection)); - } - - [StarMapUnload] - public void Unload() - { - _publisher?.Dispose(); - } -} -``` - -Only the mod that owns the event type's assembly can register its publisher, and only one publisher can be registered for each event type. Attempting to register another publisher throws. - -## Subscribing to an event - -A dependent mod can subscribe after the publisher has registered: - -```csharp -using System; -using StarMap.API; -using StarMap.API.Mediation; -using StarMap.API.Services; - -[StarMapMod] -public sealed class SelectionSubscriber -{ - private readonly IMediationService _events; - private ISubscription? _subscription; - - public SelectionSubscriber(IMediationService events) - { - _events = events; - } - - [StarMapBeforeMain] - public void Initialize() - { - _subscription = _events.Subscribe(OnSelectionChanged); - } - - private void OnSelectionChanged(SelectionChanged message) - { - Console.WriteLine($"Selection changed to {message.Selection}"); - } - - [StarMapUnload] - public void Unload() - { - _subscription?.Dispose(); - } -} -``` - -`Subscribe()` throws if a publisher for `T` has not been registered yet. Dispose subscriptions and the publisher when their respective mods unload. - -## Synchronous and parallel publishing - -`Publish` invokes subscribers synchronously. `PublishParallel` runs each handler concurrently and returns a `Task` that completes when the handlers finish. Handlers used with `PublishParallel` must be thread-safe and should not access game state unless that access is safe from a worker thread. - -## Sharing event types between mods - -The event type's assembly must be shared with each subscribing mod so both mods use the same event type. Add it to the provider's `ExportedAssemblies` and the consumer's `ImportedAssemblies`. The consumer must also declare the provider as a required dependency if it subscribes during startup. See [mod dependencies](dependencies.md#sharing-event-types-between-mods) for the configuration example. diff --git a/docs/modding/index.md b/docs/modding/index.md index 1c7922d..81c7629 100644 --- a/docs/modding/index.md +++ b/docs/modding/index.md @@ -15,7 +15,7 @@ HelloStarMap/ `-- any private dependency assemblies ``` -Start with the [first-mod walkthrough](first-mod.md). Then read about [lifecycle callbacks](lifecycle.md), [services and mechanics](services.md), and [mod dependencies](dependencies.md). The service overview links to separate guides for [constructor injection](constructor-injection.md), [mod-provided services](mod-services.md), [menu items](mod-menu.md), [event mediation](event-mediation.md), and [method patching](patching.md). +Start with the [first-mod walkthrough](first-mod.md). Then read about [lifecycle callbacks](lifecycle.md), [services and mechanics](services.md), and [mod dependencies](dependencies.md). The service overview links to separate guides for [constructor injection](constructor-injection.md), [mod-provided services](mod-services.md), [menu items](mod-menu.md), the [typed event bus](event-bus.md), and [method patching](patching.md). ## Entry assembly and mod ID diff --git a/docs/modding/lifecycle.md b/docs/modding/lifecycle.md index 3fe00f1..70c9dcd 100644 --- a/docs/modding/lifecycle.md +++ b/docs/modding/lifecycle.md @@ -18,4 +18,4 @@ The callback methods return `void`. Use the exact parameter types and counts; me ## Constructor-injected services -StarMap provides `IModServiceRegistry`, `IModMenuService`, `IMediationService`, and `IPatchService` through the entry class constructor. See [constructor injection](constructor-injection.md) for the injection mechanism and the individual pages for [mod-provided services](mod-services.md), [menu items](mod-menu.md), [event mediation](event-mediation.md), and [method patching](patching.md) for their usage. +StarMap provides `IModServiceRegistry`, `IModMenuService`, `IEventBus`, and `IPatchService` through the entry class constructor. See [constructor injection](constructor-injection.md) for the injection mechanism and the individual pages for [mod-provided services](mod-services.md), [menu items](mod-menu.md), the [typed event bus](event-bus.md), and [method patching](patching.md) for their usage. diff --git a/docs/modding/mod-services.md b/docs/modding/mod-services.md index 91c2185..d0e08b0 100644 --- a/docs/modding/mod-services.md +++ b/docs/modding/mod-services.md @@ -1,6 +1,6 @@ # Mod-provided services -`IModServiceRegistry` lets a provider mod expose an object through a shared service contract so dependent mods can use it. This is separate from StarMap's built-in services such as `IModMenuService` and `IMediationService`. +`IModServiceRegistry` lets a provider mod expose an object through a shared service contract so dependent mods can use it. This is separate from StarMap's built-in services such as `IModMenuService` and `IEventBus`. ## Define and share a contract diff --git a/docs/modding/services.md b/docs/modding/services.md index cf43e41..70a0573 100644 --- a/docs/modding/services.md +++ b/docs/modding/services.md @@ -5,7 +5,7 @@ StarMap provides core services and a registry for services shared between mods. - [Constructor injection](constructor-injection.md) - [Mod-provided services](mod-services.md) with `IModServiceRegistry` - [In-game menu items](mod-menu.md) with `IModMenuService` -- [Typed event mediation](event-mediation.md) with `IMediationService` +- [Typed event bus](event-bus.md) with `IEventBus` - [Method patching](patching.md) with `IPatchService` For entry-point method signatures, see [lifecycle callbacks](lifecycle.md). For declaring mod dependencies and sharing assemblies, see [mod dependencies](dependencies.md). diff --git a/mkdocs.yml b/mkdocs.yml index f1d65f2..183ff7f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,7 +34,7 @@ nav: - Constructor injection: modding/constructor-injection.md - Mod-provided services: modding/mod-services.md - In-game menu items: modding/mod-menu.md - - Typed event mediation: modding/event-mediation.md + - Typed event bus: modding/event-bus.md - Method patching: modding/patching.md - Dependencies: modding/dependencies.md - Maintainers: maintainers.md