namespace MrGameEng.Core; /// /// Minimal service locator used by engine modules to expose their services /// (input, audio, assets, …) to scenes and systems without coupling modules to each other. /// public sealed class ServiceRegistry { private readonly Dictionary _services = new(); /// Registers a service instance under type . Throws if already registered. public void Add(T service) where T : class { if (!_services.TryAdd(typeof(T), service)) { throw new InvalidOperationException($"Service of type {typeof(T)} is already registered."); } } /// Returns the registered service of type . Throws if missing. public T Get() where T : class { return _services.TryGetValue(typeof(T), out var service) ? (T)service : throw new InvalidOperationException($"Service of type {typeof(T)} is not registered."); } /// Returns the registered service of type or null. public T? GetOrDefault() where T : class { return _services.TryGetValue(typeof(T), out var service) ? (T)service : null; } /// /// Disposes every registered service (each instance once, even /// when registered under several types) and clears the registry. /// is skipped. Called on host shutdown. /// internal void DisposeServices(object? except = null) { var disposed = new HashSet(ReferenceEqualityComparer.Instance); foreach (var service in _services.Values) { if (!ReferenceEquals(service, except) && service is IDisposable disposable && disposed.Add(service)) { disposable.Dispose(); } } _services.Clear(); } }