using System.Threading; using Cysharp.Threading.Tasks; using R3; using RebootKit.Engine.Foundation; using RebootKit.Engine.Main; using RebootKit.Engine.Services.Simulation; namespace RebootKit.Engine.Services.GameMode { public class GameModesService : IService { static readonly Logger s_logger = new(nameof(GameModesService)); [Inject] DIContext m_DIContext; GameModeAsset m_GameModeAsset; readonly CancellationTokenSource m_DestroyCancellationTokenSource = new(); DisposableBag m_ActiveGameModeDisposableBag; readonly ReactiveProperty m_ActiveGameMode = new(null); public ReadOnlyReactiveProperty ActiveGameMode => m_ActiveGameMode; public void Dispose() { m_DestroyCancellationTokenSource.Cancel(); m_DestroyCancellationTokenSource.Dispose(); m_ActiveGameModeDisposableBag.Dispose(); } public void Start(GameModeAsset asset, WorldConfig worldConfig) { if (m_ActiveGameMode.Value != null) { s_logger.Warning("Game is already running"); return; } Stop(); m_ActiveGameModeDisposableBag = new DisposableBag(); m_ActiveGameMode.Value = asset.Create(m_DIContext); m_ActiveGameModeDisposableBag.Add(m_ActiveGameMode); InitializeGameModeAsync(worldConfig, CancellationToken.None).Forget(); } async UniTask InitializeGameModeAsync(WorldConfig worldConfig, CancellationToken cancellationToken) { await m_ActiveGameMode.Value.OnInit(m_DestroyCancellationTokenSource.Token); await RR.World.LoadAsync(worldConfig, cancellationToken); m_ActiveGameMode.Value.OnStart(); Observable.EveryUpdate().Subscribe(_ => { m_ActiveGameMode.Value?.OnTick(); }).AddTo(ref m_ActiveGameModeDisposableBag); } public void Stop() { if (m_ActiveGameMode.Value == null) { return; } m_ActiveGameMode.Value.OnStop(); m_ActiveGameMode.Value = null; m_ActiveGameModeDisposableBag.Dispose(); } } }