using System;
using EcsRx.Components.Database;
using EcsRx.Components.Lookups;
using EcsRx.Entities;
using EcsRx.Extensions;
using EcsRx.Groups;
using EcsRx.Groups.Observable;
using EcsRx.MicroRx.Disposables;
using EcsRx.MicroRx.Extensions;
using EcsRx.Systems;
using EcsRx.Threading;
namespace EcsRx.Plugins.Batching.Systems
{
public abstract class ManualBatchedSystem : IManualSystem
{
public abstract IGroup Group { get; }
public IComponentDatabase ComponentDatabase { get; }
public IComponentTypeLookup ComponentTypeLookup { get; }
public IThreadHandler ThreadHandler { get; }
protected IObservableGroup ObservableGroup { get; private set; }
protected bool ShouldParallelize { get; private set; }
protected IDisposable Subscriptions;
protected ManualBatchedSystem(IComponentDatabase componentDatabase, IComponentTypeLookup componentTypeLookup, IThreadHandler threadHandler)
{
ComponentDatabase = componentDatabase;
ComponentTypeLookup = componentTypeLookup;
ThreadHandler = threadHandler;
}
protected abstract void RebuildBatch();
///
/// This describes when the system should be processed
///
/// A trigger indicating that the process should run
protected abstract IObservable ReactWhen();
///
/// Do anything before the batch gets processed
///
protected virtual void BeforeProcessing(){}
///
/// Do anything after the batch has been processed
///
protected virtual void AfterProcessing(){}
///
/// The wrapper for processing the underlying batch
///
protected abstract void ProcessBatch();
public virtual void StartSystem(IObservableGroup observableGroup)
{
ObservableGroup = observableGroup;
ShouldParallelize = this.ShouldMutliThread();
var subscriptions = new CompositeDisposable();
ProcessGroupSubscription(ObservableGroup.OnEntityAdded).Subscribe(_ => RebuildBatch()).AddTo(subscriptions);
ProcessGroupSubscription(ObservableGroup.OnEntityRemoved).Subscribe(_ => RebuildBatch()).AddTo(subscriptions);
RebuildBatch();
ReactWhen().Subscribe(_ => RunBatch()).AddTo(subscriptions);
Subscriptions = subscriptions;
}
///
/// This processes the group level subscription, allowing you to change how the change of a group should be run
///
///
/// The observable stream that should be subscribed to
/// Out the box it will just pass through the observable but in a lot of cases you may want to
/// throttle the group changes so multiple ones within a single frame would be run once.
protected virtual IObservable ProcessGroupSubscription(IObservable groupChange)
{ return groupChange; }
private void RunBatch()
{
BeforeProcessing();
ProcessBatch();
AfterProcessing();
}
public virtual void StopSystem(IObservableGroup observableGroup)
{ Subscriptions.Dispose(); }
}
}