using System; using System.Collections.Generic; // Реестр модулей: модуль регистрирует свой контракт, остальные получают его отсюда. // Так модули не ссылаются на классы друг друга: Армия знает про IEconomy, но не про ResourceManager. // // GameServices.Register(this); // в модуле Экономики // GameServices.Get().TrySpend(ResourceType.Food, 15); // в любом другом модуле public static class GameServices { private static readonly Dictionary services = new Dictionary(); public static void Register(T service) where T : class { services[typeof(T)] = service ?? throw new ArgumentNullException(nameof(service)); } // Снимает регистрацию, только если зарегистрирован именно этот экземпляр // (дубликат синглтона, уничтожаясь, не должен снять настоящий) public static void Unregister(T service) where T : class { if (services.TryGetValue(typeof(T), out object current) && ReferenceEquals(current, service)) services.Remove(typeof(T)); } public static T Get() where T : class { if (services.TryGetValue(typeof(T), out object service)) return (T)service; throw new InvalidOperationException( $"Модуль {typeof(T).Name} не зарегистрирован. Проверь, что он есть на сцене или в App/GameModules."); } public static bool TryGet(out T service) where T : class { if (services.TryGetValue(typeof(T), out object found)) { service = (T)found; return true; } service = null; return false; } public static bool Has() where T : class { return services.ContainsKey(typeof(T)); } // Полная очистка -- при старте игры (в редакторе статика может пережить прошлый запуск) public static void Clear() { services.Clear(); } }