├── .gitbook.yaml ├── .gitignore ├── LICENSE ├── README.md ├── appveyor.yml ├── build ├── nuget.exe └── pack.bat ├── docs ├── architecture │ ├── entity-collections.md │ └── high-level-architecture.md ├── breaking-changes.md ├── diagrams │ ├── diagrams.eddx │ ├── event-propagation.png │ └── high-level-architecture.png ├── framework │ ├── blueprints.md │ ├── components.md │ ├── entities.md │ ├── groups.md │ ├── observable-groups.md │ └── systems.md ├── infrastructure │ ├── application-infrastructure.md │ ├── application-lifecycle.md │ └── dependency-injection-abstraction.md ├── introduction │ ├── setup.md │ └── stuff-to-know.md ├── others │ ├── faqs-etc.md │ ├── microrx.md │ └── third-party-content.md ├── performance │ ├── component-type-lookups.md │ ├── readme.md │ ├── struct-components.md │ └── system-affinity.md ├── plugins │ ├── batched-plugin.md │ ├── computed-plugin.md │ ├── group-binding-plugin.md │ ├── persistence-plugin.md │ ├── reactive-systems-plugin.md │ ├── readme.md │ └── view-plugin.md ├── readme.md └── summary.md └── src ├── EcsRx.Benchmarks ├── Benchmarks │ ├── EntityAddComponentsBenchmark.cs │ ├── EntityGroupMatchingBenchmark.cs │ ├── EntityRetrievalBenchmark.cs │ ├── ExecutorAddAndRemoveEntitiesBenchmark.cs │ ├── MultipleObservableGroupsAddAndRemoveBenchmark.cs │ └── ObservableGroupsAddAndRemoveBenchmark.cs ├── EcsRx.Benchmarks.csproj ├── EcsRxBenchmark.cs └── Program.cs ├── EcsRx.Examples ├── Application │ └── EcsRxConsoleApplication.cs ├── Custom │ ├── Components │ │ └── FirstComponent.cs │ ├── Groups │ │ └── MessageGroup.cs │ ├── SetupSystemPriorityApplication.cs │ └── Systems │ │ ├── FirstSystem.cs │ │ └── SecondSystem.cs ├── EcsRx.Examples.csproj ├── ExampleApps │ ├── BatchedGroupExample │ │ ├── BatchedGroupExampleApplication.cs │ │ ├── Blueprints │ │ │ └── MoveableBlueprint.cs │ │ ├── Components │ │ │ ├── MovementSpeedComponent.cs │ │ │ ├── NameComponent.cs │ │ │ └── PositionComponent.cs │ │ ├── Lookups │ │ │ └── ComponentLookupTypes.cs │ │ ├── Modules │ │ │ └── CustomComponentLookupsModule.cs │ │ └── Systems │ │ │ ├── BatchedMovementSystem.cs │ │ │ ├── LoggingSystem.cs │ │ │ └── SpawnerSystem.cs │ ├── ComputedGroupExample │ │ ├── Blueprints │ │ │ └── CharacterBlueprint.cs │ │ ├── Components │ │ │ ├── HasHealthComponent.cs │ │ │ └── HasNameComponent.cs │ │ ├── ComputedGroupExampleApplication.cs │ │ ├── ComputedGroups │ │ │ ├── ILowestHealthComputedGroup.cs │ │ │ └── LowestHealthComputedGroup.cs │ │ ├── Extensions │ │ │ └── IEntityExtensions.cs │ │ ├── Modules │ │ │ └── ComputedModule.cs │ │ └── Systems │ │ │ ├── DisplayLowestHealthSystem.cs │ │ │ └── RandomlyChangeHp.cs │ ├── DataPipelinesExample │ │ ├── Components │ │ │ └── PlayerStateComponent.cs │ │ ├── Events │ │ │ └── SavePipelineEvent.cs │ │ ├── Modules │ │ │ └── PipelineModule.cs │ │ ├── PersistDataApplication.cs │ │ ├── Pipelines │ │ │ └── PostJsonHttpPipeline.cs │ │ └── Systems │ │ │ ├── PlayerStateUpdaterGroupSystem.cs │ │ │ └── TriggerPipelineSystem.cs │ ├── HealthExample │ │ ├── Blueprints │ │ │ └── EnemyBlueprint.cs │ │ ├── Components │ │ │ └── HealthComponent.cs │ │ ├── Events │ │ │ └── EntityDamagedEvent.cs │ │ ├── HealthExampleApplication.cs │ │ └── Systems │ │ │ ├── DisplayHealthChangesSystem.cs │ │ │ └── TakeDamageSystem.cs │ ├── HelloWorldExample │ │ ├── Components │ │ │ └── CanTalkComponent.cs │ │ ├── HelloWorldExampleApplication.cs │ │ └── Systems │ │ │ └── TalkingGroupSystem.cs │ ├── LoadingEntityDatabase │ │ ├── Blueprints │ │ │ └── RandomEntityBlueprint.cs │ │ ├── Components │ │ │ ├── DummyComponent1.cs │ │ │ └── DummyComponent2.cs │ │ ├── LoadingEntityDatabaseApplication.cs │ │ └── Modules │ │ │ ├── EnableNumericsModule.cs │ │ │ ├── EntityDebugModule.cs │ │ │ └── JsonEntityDatabaseModule.cs │ ├── Performance │ │ ├── Components │ │ │ ├── SimpleReadComponent.cs │ │ │ ├── SimpleWriteComponent.cs │ │ │ └── Specific │ │ │ │ └── Components.cs │ │ ├── EntityPerformanceApplication.cs │ │ ├── Extensions │ │ │ └── IEnumerableExtensions.cs │ │ ├── GroupPerformanceApplication.cs │ │ ├── Helper │ │ │ └── RandomGroupFactory.cs │ │ ├── MakingLotsOfEntitiesApplication.cs │ │ ├── Modules │ │ │ └── CustomFrameworkModule.cs │ │ ├── ObservableGroupPerformanceApplication.cs │ │ ├── OptimizedEntityPerformanceApplication.cs │ │ ├── OptimizedGroupPerformanceApplication.cs │ │ ├── SimpleSystemApplication.cs │ │ └── Systems │ │ │ ├── ExampleBatchedSystem.cs │ │ │ └── ExampleReactToGroupSystem.cs │ └── Playground │ │ ├── BasicLoopApplication.cs │ │ ├── Batches │ │ ├── CustomClassBatch.cs │ │ ├── CustomStructBatch.cs │ │ └── CustomUnsafeStructBatch.cs │ │ ├── ClassBased │ │ ├── Class1Application.cs │ │ ├── Class2Application.cs │ │ ├── Class3Application.cs │ │ └── Class4Application.cs │ │ ├── Components │ │ ├── ClassComponent.cs │ │ ├── ClassComponent2.cs │ │ ├── StructComponent.cs │ │ └── StructComponent2.cs │ │ └── StructBased │ │ ├── Struct1Application.cs │ │ ├── Struct2Application.cs │ │ ├── Struct3Application.cs │ │ ├── Struct3BApplication.cs │ │ ├── Struct3CApplication.cs │ │ ├── Struct4Application.cs │ │ └── Struct4BApplication.cs ├── Extensions │ └── IObservableExtensions.cs └── Program.cs ├── EcsRx.Infrastructure ├── EcsRx.Infrastructure.csproj ├── EcsRxApplication.cs ├── Extensions │ ├── IDependencyContainerExtensions.cs │ └── IEcsRxApplicationExtensions.cs ├── IEcsRxApplication.cs └── Modules │ └── EcsRxInfrastructureModule.cs ├── EcsRx.Plugins.Batching ├── Accessors │ ├── AccessorToken.cs │ ├── BatchAccessor.cs │ ├── BatchManager.cs │ ├── IBatchAccessor.cs │ ├── IBatchManager.cs │ ├── IReferenceBatchAccessor.cs │ └── ReferenceBatchAccessor.cs ├── BatchPlugin.cs ├── Batches │ ├── Batch.cs │ ├── PinnedBatch.cs │ └── ReferenceBatch.cs ├── Builders │ ├── BatchBuilder.cs │ ├── IBatchBuilder.cs │ ├── IReferenceBatchBuilder.cs │ └── ReferenceBatchBuilder.cs ├── EcsRx.Plugins.Batching.csproj ├── Factories │ ├── BatchBuilderFactory.cs │ ├── IBatchBuilderFactory.cs │ ├── IReferenceBatchBuilderFactory.cs │ └── ReferenceBatchBuilderFactory.cs └── Systems │ ├── BatchedSystem.cs │ ├── ManualBatchedSystem.cs │ └── ReferenceBatchedSystem.cs ├── EcsRx.Plugins.GroupBinding ├── Attributes │ ├── FromComponentsAttribute.cs │ └── FromGroupAttribute.cs ├── EcsRx.Plugins.GroupBinding.csproj ├── Exceptions │ └── MissingGroupSystemInterfaceException.cs ├── GroupBindingsPlugin.cs ├── Groups │ └── GroupWithAffinity.cs └── Systems │ └── Handlers │ └── GroupBindingSystemHandler.cs ├── EcsRx.Plugins.Persistence ├── Builders │ ├── EcsRxPipelineBuilder.cs │ ├── EcsRxPipelineNeedsDataBuilder.cs │ └── EcsRxPipelineNeedsObjectBuilder.cs ├── Data │ ├── EntityCollectionData.cs │ ├── EntityData.cs │ └── EntityDatabaseData.cs ├── EcsRx.Plugins.Persistence.csproj ├── EcsRxPersistedApplication.cs ├── Extensions │ └── IDependencyContainerExtensions.cs ├── Modules │ ├── LazyDataModule.cs │ └── PersistityModule.cs ├── PersistencePlugin.cs ├── Pipelines │ ├── DefaultLoadEntityDatabasePipeline.cs │ ├── DefaultSaveEntityDatabasePipeline.cs │ ├── EcsRxBuiltPipeline.cs │ ├── ILoadEntityDatabasePipeline.cs │ └── ISaveEntityDatabasePipeline.cs └── Transformers │ ├── FromEntityCollectionDataTransformer.cs │ ├── FromEntityDataTransformer.cs │ ├── FromEntityDatabaseDataTransformer.cs │ ├── IFromEntityCollectionDataTransformer.cs │ ├── IFromEntityDataTransformer.cs │ ├── IFromEntityDatabaseDataTransformer.cs │ ├── IToEntityCollectionDataTransformer.cs │ ├── IToEntityDataTransformer.cs │ ├── IToEntityDatabaseDataTransformer.cs │ ├── ToEntityCollectionDataTransformer.cs │ ├── ToEntityDataTransformer.cs │ └── ToEntityDatabaseDataTransformer.cs ├── EcsRx.Plugins.Transforms ├── Components │ ├── Transform2DComponent.cs │ └── TransformComponent.cs ├── EcsRx.Plugins.Transforms.csproj └── TransformsPlugin.cs ├── EcsRx.Plugins.Views ├── Components │ └── ViewComponent.cs ├── EcsRx.Plugins.Views.csproj ├── Extensions │ └── IEcsRxApplicationExtensions.cs ├── Pooling │ ├── IViewPool.cs │ ├── ViewObjectContainer.cs │ └── ViewPool.cs ├── Systems │ ├── IViewResolverSystem.cs │ ├── PooledViewResolverSystem.cs │ └── ViewResolverSystem.cs ├── ViewHandlers │ └── IViewHandler.cs └── ViewsPlugin.cs ├── EcsRx.Tests ├── EcsRx.Tests.csproj ├── EcsRx │ ├── Components │ │ └── Lookups │ │ │ └── ComponentTypeLookupTests.cs │ ├── Computeds │ │ ├── ComputedCollectionFromGroupTests.cs │ │ ├── ComputedFromGroupTests.cs │ │ ├── ComputedGroupTests.cs │ │ └── Models │ │ │ ├── TestComputedCollectionFromGroup.cs │ │ │ ├── TestComputedFromGroup.cs │ │ │ └── TestComputedGroup.cs │ ├── Database │ │ ├── ComponentDatabaseTests.cs │ │ ├── EntityCollectionTests.cs │ │ ├── EntityDatabaseExtensionTests.cs │ │ └── EntityDatabaseTests.cs │ ├── EntityTests.cs │ ├── Handlers │ │ ├── BasicEntitySystemHandlerTests.cs │ │ ├── ReactToDataSystemHandlerTests.cs │ │ ├── ReactToEntitySystemHandlerTests.cs │ │ ├── ReactToGroupSystemHandlerTests.cs │ │ ├── SetupSystemHandlerTests.cs │ │ ├── SystemExecutorTests.cs │ │ └── TeardownSystemHandlerTests.cs │ ├── IApplicationExtensionsTests.cs │ ├── IEnumerableExtensionsTests.cs │ ├── IGroupExtensionTests.cs │ ├── ISystemExtensionTests.cs │ ├── Observables │ │ ├── Lookups │ │ │ └── ObservableGroupLookupTests.cs │ │ ├── ObservableGroupTests.cs │ │ ├── ObservableGroupTokenTests.cs │ │ └── Trackers │ │ │ ├── BatchObservableGroupTrackerTests.cs │ │ │ ├── CollectionObservableGroupTrackerTests.cs │ │ │ └── IndividualObservableGroupTrackerTests.cs │ └── Pools │ │ ├── ComponentPoolTests.cs │ │ └── ViewPoolTests.cs ├── Helpers │ └── ManualUpdateScheduler.cs ├── Models │ ├── ComplexObject.cs │ ├── ComponentWithReactiveProperty.cs │ ├── ComponentWithoutInterface.cs │ ├── TestComponentOne.cs │ ├── TestComponentThree.cs │ ├── TestComponentTwo.cs │ ├── TestDisposableComponent.cs │ ├── TestStructComponentOne.cs │ └── TestStructComponentTwo.cs ├── Plugins │ ├── Batching │ │ ├── BatchAccessorTests.cs │ │ ├── BatchBuilderTests.cs │ │ └── ReferenceBatchBuilderTests.cs │ └── GroupBinding │ │ └── Handlers │ │ ├── GroupBindingSystemHandlerTests.cs │ │ └── Helpers │ │ ├── SystemMissingGroup.cs │ │ ├── SystemWithAutoGroupPopulation.cs │ │ └── TestGroupA.cs ├── Sanity │ └── SanityTests.cs └── Systems │ ├── DeletingScenarios │ ├── DeletingBasicEntitySystem1.cs │ ├── DeletingBasicEntitySystem2.cs │ ├── DeletingOverlappingBasicEntitySystem1.cs │ ├── DeletingOverlappingBasicEntitySystem2.cs │ ├── DeletingOverlappingReactiveEntityTestSystem1.cs │ ├── DeletingOverlappingReactiveEntityTestSystem2.cs │ ├── DeletingOverlappingSetupTestSystem1.cs │ ├── DeletingOverlappingSetupTestSystem2.cs │ ├── DeletingReactiveDataTestSystem1.cs │ ├── DeletingReactiveDataTestSystem2.cs │ ├── DeletingReactiveEntityTestSystem1.cs │ ├── DeletingReactiveEntityTestSystem2.cs │ ├── DeletingSetupTestSystem1.cs │ └── DeletingSetupTestSystem2.cs │ ├── Handlers │ ├── DefaultPriorityHandler.cs │ ├── HighPriorityHandler.cs │ ├── HigherPriorityHandler.cs │ └── LowerPriorityHandler.cs │ ├── PriorityScenarios │ ├── DefaultPriorityGroupSystem.cs │ ├── HigherThanDefaultPriorityGroupSystem.cs │ ├── HighestPriorityGroupSystem.cs │ ├── LowerThanDefaultPriorityGroupSystem.cs │ └── LowestPriorityGroupSystem.cs │ ├── ReactiveDataTestSystem.cs │ ├── TestSetupSystem.cs │ └── TestViewResolverSystem.cs ├── EcsRx.sln └── EcsRx ├── Attributes └── CollectionAffinityAttribute.cs ├── Blueprints └── IBlueprint.cs ├── Collections ├── Database │ ├── EntityCollectionLookups.cs │ ├── EntityDatabase.cs │ └── IEntityDatabase.cs ├── Entity │ ├── DefaultEntityCollectionFactory.cs │ ├── EntityCollection.cs │ ├── IEntityCollection.cs │ ├── IEntityCollectionFactory.cs │ ├── IEntityCollectionQuery.cs │ ├── INotifyingCollection.cs │ ├── INotifyingEntityCollection.cs │ └── INotifyingEntityComponentChanges.cs ├── Events │ ├── CollectionElementChangedEvent.cs │ ├── CollectionEntityEvent.cs │ └── ComponentsChangedEvent.cs ├── IObservableGroupManager.cs └── ObservableGroupManager.cs ├── Components ├── Accessor │ ├── ComponentAccessor.cs │ └── IComponentAccessor.cs ├── ComponentPool.cs ├── Database │ ├── ComponentDatabase.cs │ └── IComponentDatabase.cs ├── IComponent.cs ├── IComponentPool.cs └── Lookups │ ├── ComponentTypeLookup.cs │ ├── DefaultComponentTypeAssigner.cs │ ├── IComponentTypeAssigner.cs │ ├── IComponentTypeLookup.cs │ ├── IStructDefaulter.cs │ └── StructDefaulter.cs ├── Computeds ├── Collections │ └── ComputedCollectionFromGroup.cs ├── ComputedFromGroup.cs └── Groups │ ├── ComputedGroup.cs │ └── IComputedGroup.cs ├── EcsRx.csproj ├── Entities ├── DefaultEntityFactory.cs ├── Entity.cs ├── IEntity.cs └── IEntityFactory.cs ├── Exceptions └── InvalidEntityException.cs ├── Extensions ├── EntityDatabaseExtensions.cs ├── IBlueprintExtensions.cs ├── IComponentAccessorExtensions.cs ├── IComponentDatabaseExtensions.cs ├── IComponentTypeLookupExtensions.cs ├── IEntityCollectionExtensions.cs ├── IEntityExtensions.cs ├── IEnumerableExtensions.cs ├── IGroupExtensions.cs ├── IObservableGroupExtensions.cs ├── IObservableGroupTrackerExtensions.cs ├── ISystemExtensions.cs └── LookupGroupExtensions.cs ├── Groups ├── EmptyGroup.cs ├── Group.cs ├── GroupBuilder.cs ├── GroupWithPredicate.cs ├── IGroup.cs ├── IHasPredicate.cs ├── LookupGroup.cs └── Observable │ ├── DefaultObservableObservableGroupFactory.cs │ ├── IObservableGroup.cs │ ├── IObservableGroupFactory.cs │ ├── IObservableGroupQuery.cs │ ├── ObservableGroup.cs │ ├── ObservableGroupConfiguration.cs │ ├── ObservableGroupToken.cs │ └── Tracking │ ├── Events │ └── EntityGroupStateChanged.cs │ ├── GroupTrackerFactory.cs │ ├── IGroupTrackerFactory.cs │ ├── Trackers │ ├── BatchObservableGroupTracker.cs │ ├── CollectionObservableGroupTracker.cs │ ├── IBatchObservableGroupTracker.cs │ ├── ICollectionObservableGroupTracker.cs │ ├── IIndividualObservableGroupTracker.cs │ ├── IObservableGroupTracker.cs │ ├── IndividualObservableGroupTracker.cs │ └── ObservableGroupTracker.cs │ └── Types │ ├── GroupActionType.cs │ └── GroupMatchingType.cs ├── Lookups ├── CollectionLookup.cs ├── EntityLookup.cs └── ObservableGroupLookup.cs └── Systems ├── Handlers ├── BasicEntitySystemHandler.cs ├── ReactToDataSystemHandler.cs ├── ReactToEntitySystemHandler.cs ├── ReactToGroupSystemHandler.cs ├── SetupSystemHandler.cs └── TeardownSystemHandler.cs ├── IBasicEntitySystem.cs ├── IGroupSystem.cs ├── IReactToDataSystem.cs ├── IReactToEntitySystem.cs ├── IReactToGroupExSystem.cs ├── IReactToGroupSystem.cs ├── ISetupSystem.cs └── ITeardownSystem.cs /.gitbook.yaml: -------------------------------------------------------------------------------- 1 | root: ./docs 2 | 3 | structure: 4 | readme: readme.md 5 | summary: summary.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | bin 3 | packages/ 4 | 5 | .idea/ 6 | *.user 7 | *.suo 8 | *.nupkg 9 | /src/.vs 10 | /src/EcsRx.PerformanceTests/BenchmarkDotNet.Artifacts 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 LP 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 8.0.{build} 2 | branches: 3 | only: 4 | - master 5 | - build-test 6 | image: Visual Studio 2022 7 | configuration: Release 8 | dotnet_csproj: 9 | patch: true 10 | file: '**\*.csproj' 11 | version: '{version}' 12 | package_version: '{version}' 13 | assembly_version: '{version}' 14 | file_version: '{version}' 15 | informational_version: '{version}' 16 | before_build: 17 | - cmd: nuget restore src/EcsRx.sln 18 | build: 19 | project: src/EcsRx.sln 20 | publish_nuget: true 21 | verbosity: minimal 22 | artifacts: 23 | - path: '**\*.nupkg' 24 | deploy: 25 | provider: NuGet 26 | on: 27 | APPVEYOR_REPO_TAG: true 28 | server: 29 | api_key: 30 | secure: xItHI+jcoXOw7VZoVj1gGOiH2zajMnpq0wQgXlp0SEl5PlAQ7epxowtpbqID7a4V 31 | skip_symbols: true 32 | symbol_server: 33 | artifact: /.*\.nupkg/ 34 | -------------------------------------------------------------------------------- /build/nuget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EcsRx/ecsrx/448e0bcd911190e6ab394b31e7584902569d6682/build/nuget.exe -------------------------------------------------------------------------------- /build/pack.bat: -------------------------------------------------------------------------------- 1 | set version=7.0.0 2 | dotnet pack ../src/EcsRx -c Release -o ../../_dist /p:version=%version% 3 | dotnet pack ../src/EcsRx.Plugins.ReactiveSystems -c Release -o ../../_dist /p:version=%version% 4 | dotnet pack ../src/EcsRx.Plugins.Views -c Release -o ../../_dist /p:version=%version% 5 | dotnet pack ../src/EcsRx.Plugins.Computeds -c Release -o ../../_dist /p:version=%version% 6 | dotnet pack ../src/EcsRx.Plugins.GroupBinding -c Release -o ../../_dist /p:version=%version% 7 | dotnet pack ../src/EcsRx.Plugins.Batching -c Release -o ../../_dist /p:version=%version% 8 | dotnet pack ../src/EcsRx.Plugins.Transforms -c Release -o ../../_dist /p:version=%version% 9 | dotnet pack ../src/EcsRx.Infrastructure -c Release -o ../../_dist /p:version=%version% 10 | dotnet pack ../src/EcsRx.Infrastructure.Ninject -c Release -o ../../_dist /p:version=%version% 11 | dotnet pack ../src/EcsRx.ReactiveData -c Release -o ../../_dist /p:version=%version% -------------------------------------------------------------------------------- /docs/diagrams/diagrams.eddx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EcsRx/ecsrx/448e0bcd911190e6ab394b31e7584902569d6682/docs/diagrams/diagrams.eddx -------------------------------------------------------------------------------- /docs/diagrams/event-propagation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EcsRx/ecsrx/448e0bcd911190e6ab394b31e7584902569d6682/docs/diagrams/event-propagation.png -------------------------------------------------------------------------------- /docs/diagrams/high-level-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EcsRx/ecsrx/448e0bcd911190e6ab394b31e7584902569d6682/docs/diagrams/high-level-architecture.png -------------------------------------------------------------------------------- /docs/framework/components.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | Components are the data containers in the ECS world and should only contain some properties to contain data, there should be no logic in components, if there is logic then you are probably a bad man and need to step away from the computer. 4 | 5 | ## Using components 6 | 7 | You will need to make your own implementations of `IComponent` which encapsulate the data your components need to expose to the systems. It is fairly simple really just implement `IComponent` and it just does its stuff. 8 | 9 | ## Composition 10 | 11 | So the whole point behind components are that they can contain anything, so if you need to contain complex data it would make sense to go write a c# POCO somewhere to encapsulate your data then just include that via composition inside your component. -------------------------------------------------------------------------------- /docs/infrastructure/application-infrastructure.md: -------------------------------------------------------------------------------- 1 | # Infrastructure 2 | 3 | As part of EcsRx there is some basic infrastructure provided for you (if you choose to use `EcsRx.Infrastructure`), this contains: 4 | 5 | - A dependency injection abstraction system (So you can consume DI on any platform with any DI framework) 6 | - An `IEcsRxApplication` interface as well as a default implementation `EcsRxApplication` (So you can start your app in a consistent way) 7 | - A plugin framework via `IEcsRxPlugin` (so you can write your own plugins which can be re-used accross many projects and shared with others) 8 | - A default `EventSystem` (So you can send events around your application, which implements `IEventSystem`) 9 | 10 | All of this combined basically provides you an entry point to start creating your applications. 11 | 12 | ## Why use this? 13 | 14 | To have some sort of consistency and contract in place for extensibility, for example by adding the infrastructure you can out the box consume any EcsRx plugins (assuming they dont contain any native platform code), you can also make use of specific lifetime methods and conventions. 15 | 16 | If you have a specific scenario and dont want to use the built in infrastructure then can easily just ignore this and put your own stuff in place, but this would then mean you are then incompatible with a lot of good stuff that comes with the consistency and the community all adhering to those contracts. 17 | -------------------------------------------------------------------------------- /docs/others/third-party-content.md: -------------------------------------------------------------------------------- 1 | # Third Party Content! 2 | 3 | Big thanks to all the community who help out with SystemsRx/EcsRx. 4 | 5 | ## Hey, I want to have my plugin listed too! 6 | 7 | Great stuff buddy, all you need to do is add it here in a PR with a link to the plugin (with optional profile link) and a blurb about what the plugin is/does, or if you don't fancy that just raise an issue detailing the above and we can add it for you. 8 | 9 | --- 10 | 11 | ## Community Plugins 12 | 13 | ### [EcsRx.Plugins.UnityUx](https://github.com/Cosmic-Shores/EcsRx.Plugins.UnityUx) - By [Fijo](https://github.com/Fijo) 14 | 15 | > A minimalistic MVVM framework for the new Unity UI Toolkit build on EcsRx 16 | 17 | --- 18 | 19 | ## Community Examples/Tutorials 20 | 21 | ### [Unity Roguelike 2d in EcsRx](https://github.com/EcsRx/ecsrx.roguelike2d) 22 | 23 | > This was an official EcsRx example for unity consumers but it's often forgotten so adding it here. 24 | 25 | ### [Battle Kill 9000](https://github.com/grofit/battle-kill-9000) by [Grofit](https://github.com/grofit) 26 | 27 | > A simple web based auto battler made using SystemRx, OpenRpg and Blazor. It was mainly done as a live stream but the repo can be used to see how to run SystemsRx/EcsRx in the browser. 28 | 29 | --- 30 | 31 | ## Games Made With EcsRx 32 | -------------------------------------------------------------------------------- /docs/performance/readme.md: -------------------------------------------------------------------------------- 1 | # Performance 2 | 3 | So out the box EcsRx is average performance, and that may be fine for a lot of users, however with a few changes you can get everything running up to 10x faster in some cases. 4 | 5 | This section will provide information on each thing you can do to improve performance, and why performance is improved. One of the quickest and easiest things you can do to get a MASSIVE performance boost is to use the batched system plugin which will out the box provide massive performance gains assuming you can tell it up front what components you are going to need. 6 | 7 | If want to get maximum performance out of the library then have a read over the topics in this section, if you are happy with out the box performance then no need to continue. -------------------------------------------------------------------------------- /docs/performance/system-affinity.md: -------------------------------------------------------------------------------- 1 | # System Affinities for collections 2 | 3 | Out the box `ObservableGroups` will just listen to changes across all collections, but you can give them an affinity so they will only listen to changes on certain collections, providing a performance boost as they dont need to listen to changes on entities they will never interact with, however most of the time you are not creating observable groups as they are requested per system. So we need to be able to tell the system what affinity they have so you can have a better suited observable group. 4 | 5 | ```csharp 6 | // Tell this system that it should only interact with collections with id 1,5,6 7 | [CollectionAffinity(1,5,6)] 8 | public class SomeSystemWithAffinity : ISetupSystem 9 | { 10 | // ... 11 | } 12 | ``` 13 | 14 | If no affinity is provided then the observable group requested will just listen for changes on all collections, however if an affinity is provided you will only be listening to changes on the collections you care about. 15 | 16 | ## How much of a performance boost is this? 17 | 18 | **It's a big boost.** 19 | 20 | One of the slowest parts of the system is group resolving, as every change has to be checked against observable groups to see if it needs to pump out changes to systems, i.e a component being added may invalidate an entity in a group, or cause an entity to be added to a group. 21 | 22 | So although the checking is quite fast, it happens SOOOOOOOooooo often that it can take up a sizeable chunk of time the more groups and entities you have, as out the box each change will go to each observable group to ignore/process. 23 | 24 | You wont really notice the difference until you have tens of observable groups and hundreds of entities, but if you have thousands of entities and hundreds of observable groups you will be thankful you have partitioned out to reduce chatter. -------------------------------------------------------------------------------- /docs/plugins/group-binding-plugin.md: -------------------------------------------------------------------------------- 1 | # Group Binding Plugin 2 | 3 | Please note that this plugin isn't enabled by default and you have to load it yourself. 4 | 5 | Sometimes you just want an easy access to an `IObservableGroup` based on a group without having to start injecting a `IObservableGroupManager` by hand every time to provide you with it. 6 | Using this Plugin enables you to just add a `FromGroupAttribute` or a `FromComponentsAttribute` to any public field or any property with a public setter of the type `IObservableGroup` on your system. 7 | 8 | If your system is an `IGroupSystem` you can also use the `FromGroupAttribute` without even supplying a group to it and it'll fall back to using the value from the `IGroupSystem.Group`. 9 | 10 | # System Affinities in this plugin 11 | 12 | Please refer to the article about system affinities within the performance category for general info about the concept. 13 | 14 | By accompanying your `FromGroupAttribute`/ `FromComponentsAttribute` by a `CollectionAffinityAttribute` you can specify which collectionIds are to be observed the specified group. 15 | If you are using the `FromGroupAttribute` without supplying any arguments, it'll also consider a `CollectionAffinityAttribute` on your systems class. However you can still overwrite this by also supplying a `CollectionAffinityAttribute` to that member. 16 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # HELLO 2 | 3 | Welcome etc! 4 | 5 | > If you are viewing this in github you can view the book version of it [HERE](https://ecsrx.gitbook.io/project/) 6 | 7 | This is an attempt to document most of the important stuff around how to use the library, it is recommended that you follow the order of the TOC, however if you are not using the gitbook version then just look at the summary.md file and follow that order. 8 | 9 | The flow is generally: 10 | 11 | - Stuff you should ideally know before using the framework 12 | - About the framework and how to use it 13 | - The bits which make up the framework and how to use them 14 | - Making larger applications with the framework 15 | - How the underlying architecture fits together 16 | - How you can extend the framework and use plugins 17 | - How to use the framework in a more performance oriented manner 18 | - Other guff 19 | 20 | Feel free to add to the docs or come on the [Discord Channel](https://discord.gg/bS2rnGz) if you need help! 21 | 22 | -------------------------------------------------------------------------------- /docs/summary.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * Getting Started 4 | * [Stuff To Know](introduction/stuff-to-know.md) 5 | * [Setup](introduction/setup.md) 6 | * The Framework 7 | * [Entities](framework/entities.md) 8 | * [Components](framework/components.md) 9 | * [Systems](framework/systems.md) 10 | * [Blueprints](framework/blueprints.md) 11 | * [Groups](framework/groups.md) 12 | * [Observable Groups](framework/observable-groups.md) 13 | * Framework Infrastructure 14 | * [Application Infrastructure](infrastructure/application-infrastructure.md) 15 | * [Application Lifecycle](infrastructure/application-lifecycle.md) 16 | * [Dependency Management](infrastructure/dependency-injection-abstraction.md) 17 | * Framework Architecture 18 | * [High Level Architecture](architecture/high-level-architecture.md) 19 | * [Entity Collections](architecture/entity-collections.md) 20 | * Plugins 21 | * [Overview](plugins/readme.md) 22 | * [Reactive Systems Plugin](plugins/reactive-systems-plugin.md) 23 | * [Computeds Plugin](plugins/computed-plugin.md) 24 | * [View Plugin](plugins/view-plugin.md) 25 | * [Batching Systems Plugin](plugins/batched-plugin.md) 26 | * [Group Binding Plugin](plugins/group-binding-plugin.md) 27 | * Performance 28 | * [Overview](performance/readme.md) 29 | * [Component Type Lookups](performance/component-type-lookups.md) 30 | * [System Affinities](performance/system-affinity.md) 31 | * [Struct Components](performance/struct-components.md) 32 | * Other 33 | * [MicroRx](others/microrx.md) 34 | * [Third Party Content](others/third-party-content.md) 35 | * [FAQs](others/faqs-etc.md) 36 | * [Breaking Changes](breaking-changes.md) -------------------------------------------------------------------------------- /src/EcsRx.Benchmarks/EcsRx.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/EcsRx.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Exporters; 2 | using BenchmarkDotNet.Loggers; 3 | using BenchmarkDotNet.Running; 4 | using EcsRx.Benchmarks.Benchmarks; 5 | using SystemsRx.Extensions; 6 | 7 | namespace EcsRx.Benchmarks 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | var benchmarks = new [] 14 | { 15 | BenchmarkConverter.TypeToBenchmarks(typeof(EntityRetrievalBenchmark)), 16 | BenchmarkConverter.TypeToBenchmarks(typeof(EntityAddComponentsBenchmark)), 17 | BenchmarkConverter.TypeToBenchmarks(typeof(EntityGroupMatchingBenchmark)), 18 | BenchmarkConverter.TypeToBenchmarks(typeof(ObservableGroupsAddAndRemoveBenchmark)), 19 | BenchmarkConverter.TypeToBenchmarks(typeof(MultipleObservableGroupsAddAndRemoveBenchmark)), 20 | BenchmarkConverter.TypeToBenchmarks(typeof(ExecutorAddAndRemoveEntitySystemBenchmark)), 21 | }; 22 | 23 | var summaries = BenchmarkRunner.Run(benchmarks); 24 | var consoleLogger = ConsoleLogger.Default; 25 | consoleLogger.Flush(); 26 | summaries.ForEachRun(x => 27 | { 28 | AsciiDocExporter.Default.ExportToLog(x, consoleLogger); 29 | consoleLogger.WriteLine(); 30 | }); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/Application/EcsRxConsoleApplication.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Infrastructure.Dependencies; 2 | using SystemsRx.Infrastructure.Ninject; 3 | using EcsRx.Infrastructure; 4 | using EcsRx.Infrastructure.Extensions; 5 | using EcsRx.Plugins.Batching; 6 | using EcsRx.Plugins.Persistence; 7 | using EcsRx.Plugins.Views; 8 | 9 | namespace EcsRx.Examples.Application 10 | { 11 | public abstract class EcsRxConsoleApplication : EcsRxApplication 12 | { 13 | public override IDependencyRegistry DependencyRegistry { get; } = new NinjectDependencyRegistry(); 14 | 15 | protected override void LoadPlugins() 16 | { 17 | RegisterPlugin(new ViewsPlugin()); 18 | RegisterPlugin(new BatchPlugin()); 19 | RegisterPlugin(new PersistencePlugin()); 20 | } 21 | 22 | protected override void StartSystems() 23 | { 24 | this.StartAllBoundReactiveSystems(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/Custom/Components/FirstComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.Custom.Components 4 | { 5 | public class FirstComponent : IComponent 6 | { 7 | public string Message { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/Custom/Groups/MessageGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Examples.Custom.Components; 3 | using EcsRx.Groups; 4 | 5 | namespace EcsRx.Examples.Custom.Groups 6 | { 7 | class MessageGroup : IGroup 8 | { 9 | public Type[] RequiredComponents { get; } = {typeof(FirstComponent) }; 10 | 11 | public Type[] ExcludedComponents { get; } = Array.Empty(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/EcsRx.Examples/Custom/SetupSystemPriorityApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Examples.Application; 3 | using EcsRx.Examples.Custom.Components; 4 | using EcsRx.Extensions; 5 | 6 | namespace EcsRx.Examples.Custom 7 | { 8 | public class SetupSystemPriorityApplication : EcsRxConsoleApplication 9 | { 10 | private bool _quit; 11 | 12 | protected override void ApplicationStarted() 13 | { 14 | var defaultPool = EntityDatabase.GetCollection(); 15 | var entity = defaultPool.CreateEntity(); 16 | 17 | entity.AddComponents(new FirstComponent()); 18 | 19 | HandleInput(); 20 | } 21 | 22 | private void HandleInput() 23 | { 24 | while (!_quit) 25 | { 26 | var keyPressed = Console.ReadKey(); 27 | if (keyPressed.Key == ConsoleKey.Escape) 28 | { _quit = true; } 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/Custom/Systems/FirstSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Attributes; 3 | using EcsRx.Entities; 4 | using EcsRx.Examples.Custom.Groups; 5 | using EcsRx.Groups; 6 | using EcsRx.Systems; 7 | 8 | namespace EcsRx.Examples.Custom.Systems 9 | { 10 | [Priority(10)] 11 | public class FirstSystem : ISetupSystem 12 | { 13 | public IGroup Group => new MessageGroup(); 14 | 15 | public void Setup(IEntity entity) 16 | { 17 | Console.WriteLine("SYSTEM 1"); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/Custom/Systems/SecondSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Attributes; 3 | using EcsRx.Entities; 4 | using EcsRx.Examples.Custom.Groups; 5 | using EcsRx.Groups; 6 | using EcsRx.Systems; 7 | 8 | namespace EcsRx.Examples.Custom.Systems 9 | { 10 | [Priority(100)] 11 | public class SecondSystem : ISetupSystem 12 | { 13 | public IGroup Group => new MessageGroup(); 14 | 15 | public void Setup(IEntity entity) 16 | { 17 | Console.WriteLine("SYSTEM 2"); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/EcsRx.Examples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | netcoreapp3.1 5 | true 6 | 8 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {AD7EB200-BF3C-433B-96D2-D114DBE5B1E2} 22 | EcsRx.Infrastructure 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/BatchedGroupExampleApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Infrastructure.Extensions; 3 | using EcsRx.Examples.Application; 4 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Blueprints; 5 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Modules; 6 | 7 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample 8 | { 9 | public class BatchedGroupExampleApplication : EcsRxConsoleApplication 10 | { 11 | private bool _quit; 12 | private int _entityCount = 2; 13 | 14 | protected override void LoadModules() 15 | { 16 | base.LoadModules(); 17 | DependencyRegistry.LoadModule(); 18 | } 19 | 20 | protected override void ApplicationStarted() 21 | { 22 | var blueprint = new MoveableBlueprint(); 23 | 24 | var defaultPool = EntityDatabase.GetCollection(); 25 | 26 | for (var i = 0; i < _entityCount; i++) 27 | { defaultPool.CreateEntity(blueprint); } 28 | 29 | HandleInput(); 30 | } 31 | 32 | private void HandleInput() 33 | { 34 | while (!_quit) 35 | { 36 | var keyPressed = Console.ReadKey(); 37 | if (keyPressed.Key == ConsoleKey.Escape) 38 | { _quit = true; } 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Blueprints/MoveableBlueprint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Blueprints; 3 | using EcsRx.Entities; 4 | using EcsRx.Extensions; 5 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Components; 6 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Lookups; 7 | 8 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Blueprints 9 | { 10 | public class MoveableBlueprint : IBlueprint 11 | { 12 | private const float MinimumMovementSpeed = 1; 13 | private const float MaximumMovementSpeed = 5; 14 | 15 | private readonly Random _random = new Random(); 16 | 17 | public void Apply(IEntity entity) 18 | { 19 | entity.AddComponent(new NameComponent {Name = $"BatchedEntity-{entity.Id}"}); 20 | entity.AddComponent(ComponentLookupTypes.PositionComponentId); 21 | 22 | ref var movementSpeedComponent = ref entity.AddComponent(ComponentLookupTypes.MovementSpeedComponentId); 23 | movementSpeedComponent.Speed = (float)_random.NextDouble() * (MaximumMovementSpeed - MinimumMovementSpeed) + MinimumMovementSpeed; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Components/MovementSpeedComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Components 4 | { 5 | public struct MovementSpeedComponent : IComponent 6 | { 7 | public float Speed; 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Components/NameComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Components 4 | { 5 | public class NameComponent : IComponent 6 | { 7 | public string Name { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Components/PositionComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using EcsRx.Components; 3 | 4 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Components 5 | { 6 | public struct PositionComponent : IComponent 7 | { 8 | public Vector3 Position; 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Lookups/ComponentLookupTypes.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Lookups 2 | { 3 | public static class ComponentLookupTypes 4 | { 5 | public static int NameComponentId = 0; 6 | public static int PositionComponentId = 1; 7 | public static int MovementSpeedComponentId = 2; 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Modules/CustomComponentLookupsModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SystemsRx.Infrastructure.Dependencies; 4 | using SystemsRx.Infrastructure.Extensions; 5 | using EcsRx.Components.Lookups; 6 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Components; 7 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Lookups; 8 | 9 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Modules 10 | { 11 | public class CustomComponentLookupsModule : IDependencyModule 12 | { 13 | public void Setup(IDependencyRegistry registry) 14 | { 15 | registry.Unbind(); 16 | var explicitTypeLookups = new Dictionary 17 | { 18 | {typeof(NameComponent), ComponentLookupTypes.NameComponentId}, 19 | {typeof(PositionComponent), ComponentLookupTypes.PositionComponentId}, 20 | {typeof(MovementSpeedComponent), ComponentLookupTypes.MovementSpeedComponentId} 21 | }; 22 | var explicitComponentLookup = new ComponentTypeLookup(explicitTypeLookups); 23 | registry.Bind(new BindingConfiguration{ToInstance = explicitComponentLookup}); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Systems/BatchedMovementSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using System.Reactive.Linq; 4 | using SystemsRx.Threading; 5 | using EcsRx.Collections; 6 | using EcsRx.Components.Database; 7 | using EcsRx.Components.Lookups; 8 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Components; 9 | using EcsRx.Plugins.Batching.Factories; 10 | using EcsRx.Plugins.Batching.Systems; 11 | 12 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Systems 13 | { 14 | public class BatchedMovementSystem : BatchedSystem 15 | { 16 | public BatchedMovementSystem(IComponentDatabase componentDatabase, IComponentTypeLookup componentTypeLookup, IBatchBuilderFactory batchBuilderFactory, IThreadHandler threadHandler, IObservableGroupManager observableGroupManager) 17 | : base(componentDatabase, componentTypeLookup, batchBuilderFactory, threadHandler, observableGroupManager) 18 | {} 19 | 20 | protected override IObservable ReactWhen() 21 | { return Observable.Interval(TimeSpan.FromSeconds(0.5f)).Select(x => true); } 22 | 23 | protected override void Process(int entityId, ref PositionComponent positionComponent, ref MovementSpeedComponent movementSpeedComponent) 24 | { 25 | positionComponent.Position += Vector3.One * movementSpeedComponent.Speed; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Systems/LoggingSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Entities; 4 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Components; 5 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Lookups; 6 | using EcsRx.Extensions; 7 | using EcsRx.Groups; 8 | using EcsRx.Groups.Observable; 9 | using EcsRx.Systems; 10 | 11 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Systems 12 | { 13 | public class LoggingSystem : IReactToGroupExSystem 14 | { 15 | public IGroup Group { get; } = new Group(typeof(NameComponent), typeof(PositionComponent)); 16 | 17 | public IObservable ReactToGroup(IObservableGroup observableGroup) 18 | { return Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => observableGroup); } 19 | 20 | public void Process(IEntity entity) 21 | { 22 | var nameComponent = entity.GetComponent(); 23 | var positionComponent = entity.GetComponent(ComponentLookupTypes.PositionComponentId); 24 | Console.WriteLine($"{nameComponent.Name} - {positionComponent.Position}"); 25 | } 26 | 27 | public void BeforeProcessing() 28 | { 29 | Console.SetCursorPosition(0,0); 30 | Console.Clear(); 31 | } 32 | 33 | public void AfterProcessing() {} 34 | } 35 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/BatchedGroupExample/Systems/SpawnerSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using SystemsRx.Systems.Conventional; 4 | using EcsRx.Blueprints; 5 | using EcsRx.Collections.Database; 6 | using EcsRx.Collections.Entity; 7 | using EcsRx.Examples.ExampleApps.BatchedGroupExample.Blueprints; 8 | 9 | namespace EcsRx.Examples.ExampleApps.BatchedGroupExample.Systems 10 | { 11 | public class SpawnerSystem : IManualSystem 12 | { 13 | private IDisposable _sub; 14 | private IBlueprint _blueprint = new MoveableBlueprint(); 15 | 16 | public IEntityCollection DefaultCollection { get; } 17 | 18 | public SpawnerSystem(IEntityDatabase entityDatabase) 19 | { DefaultCollection = entityDatabase.GetCollection(); } 20 | 21 | public void StartSystem() 22 | { _sub = Observable.Interval(TimeSpan.FromSeconds(2)).Subscribe(x => Spawn()); } 23 | 24 | public void Spawn() 25 | { DefaultCollection.CreateEntity(_blueprint); } 26 | 27 | public void StopSystem() 28 | { _sub.Dispose(); } 29 | } 30 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/Blueprints/CharacterBlueprint.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Blueprints; 2 | using EcsRx.Entities; 3 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.Components; 4 | using EcsRx.Extensions; 5 | 6 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.Blueprints 7 | { 8 | public class CharacterBlueprint : IBlueprint 9 | { 10 | public string Name { get; } 11 | public int Health { get; } 12 | 13 | public CharacterBlueprint(string name, int health) 14 | { 15 | Name = name; 16 | Health = health; 17 | } 18 | 19 | public void Apply(IEntity entity) 20 | { 21 | var healthComponent = new HasHealthComponent 22 | { 23 | CurrentHealth = Health, 24 | MaxHealth = Health 25 | }; 26 | 27 | var nameComponent = new HasNameComponent 28 | { 29 | Name = Name 30 | }; 31 | 32 | entity.AddComponents(nameComponent, healthComponent); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/Components/HasHealthComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.Components 4 | { 5 | public class HasHealthComponent : IComponent 6 | { 7 | public int CurrentHealth { get; set; } 8 | public int MaxHealth { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/Components/HasNameComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.Components 4 | { 5 | public class HasNameComponent : IComponent 6 | { 7 | public string Name { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/ComputedGroupExampleApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Infrastructure.Extensions; 3 | using EcsRx.Examples.Application; 4 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.Blueprints; 5 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.Modules; 6 | 7 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample 8 | { 9 | public class ComputedGroupExampleApplication : EcsRxConsoleApplication 10 | { 11 | private bool _quit; 12 | 13 | protected override void LoadModules() 14 | { 15 | base.LoadModules(); 16 | DependencyRegistry.LoadModule(); 17 | } 18 | 19 | protected override void ApplicationStarted() 20 | { 21 | var defaultPool = EntityDatabase.GetCollection(); 22 | defaultPool.CreateEntity(new CharacterBlueprint("Bob", 200)); 23 | defaultPool.CreateEntity(new CharacterBlueprint("Tom", 150)); 24 | defaultPool.CreateEntity(new CharacterBlueprint("Rolf", 150)); 25 | defaultPool.CreateEntity(new CharacterBlueprint("Mez", 100)); 26 | defaultPool.CreateEntity(new CharacterBlueprint("TP", 1000)); 27 | defaultPool.CreateEntity(new CharacterBlueprint("MasterChief", 100)); 28 | defaultPool.CreateEntity(new CharacterBlueprint("Weakling", 20)); 29 | 30 | HandleInput(); 31 | } 32 | 33 | private void HandleInput() 34 | { 35 | while (!_quit) 36 | { 37 | var keyPressed = Console.ReadKey(); 38 | if (keyPressed.Key == ConsoleKey.Escape) 39 | { _quit = true; } 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/ComputedGroups/ILowestHealthComputedGroup.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Computeds.Groups; 2 | 3 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.ComputedGroups 4 | { 5 | public interface ILowestHealthComputedGroup : IComputedGroup 6 | {} 7 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/ComputedGroups/LowestHealthComputedGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reactive.Linq; 5 | using EcsRx.Computeds.Groups; 6 | using EcsRx.Entities; 7 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.Extensions; 8 | using EcsRx.Groups.Observable; 9 | 10 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.ComputedGroups 11 | { 12 | public class LowestHealthComputedGroup : ComputedGroup, ILowestHealthComputedGroup 13 | { 14 | public LowestHealthComputedGroup(IObservableGroup internalObservableGroup) : base(internalObservableGroup) 15 | {} 16 | 17 | public override IObservable RefreshWhen() 18 | { return Observable.Interval(TimeSpan.FromMilliseconds(100)).Select(x => true); } 19 | 20 | public override bool IsEntityApplicable(IEntity entity) 21 | { 22 | var healthPercentage = entity.GetHealthPercentile(); 23 | return healthPercentage < 50; 24 | } 25 | 26 | public override IEnumerable PostProcess(IEnumerable entities) 27 | { return entities.OrderBy(x => x.GetHealthPercentile()); } 28 | 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/Extensions/IEntityExtensions.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.Components; 3 | using EcsRx.Extensions; 4 | 5 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.Extensions 6 | { 7 | public static class IEntityExtensions 8 | { 9 | public static int GetHealthPercentile(this IEntity entity) 10 | { 11 | var healthComponent = entity.GetComponent(); 12 | var percentile = healthComponent.CurrentHealth / (float) healthComponent.MaxHealth; 13 | var percentage = percentile * 100; 14 | return (int) percentage; 15 | } 16 | 17 | public static string GetHealthString(this IEntity entity) 18 | { 19 | var healthComponent = entity.GetComponent(); 20 | return $"{healthComponent.CurrentHealth}/{healthComponent.MaxHealth}"; 21 | } 22 | 23 | public static string GetName(this IEntity entity) 24 | { 25 | var nameComponent = entity.GetComponent(); 26 | return nameComponent.Name; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/Modules/ComputedModule.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Infrastructure.Dependencies; 2 | using SystemsRx.Infrastructure.Extensions; 3 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.Components; 4 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.ComputedGroups; 5 | using EcsRx.Groups; 6 | using EcsRx.Infrastructure.Extensions; 7 | 8 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.Modules 9 | { 10 | public class ComputedModule : IDependencyModule 11 | { 12 | public void Setup(IDependencyRegistry registry) 13 | { 14 | registry.Bind(x => x.ToMethod(y => 15 | { 16 | var namedHealthGroup = y.ResolveObservableGroup(new Group(typeof(HasHealthComponent), typeof(HasNameComponent))); 17 | return new LowestHealthComputedGroup(namedHealthGroup); 18 | })); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/ComputedGroupExample/Systems/RandomlyChangeHp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Entities; 4 | using EcsRx.Examples.ExampleApps.ComputedGroupExample.Components; 5 | using EcsRx.Extensions; 6 | using EcsRx.Groups; 7 | using EcsRx.Groups.Observable; 8 | using EcsRx.Systems; 9 | 10 | namespace EcsRx.Examples.ExampleApps.ComputedGroupExample.Systems 11 | { 12 | public class RandomlyChangeHpGroupSystem : IReactToGroupSystem 13 | { 14 | private const int HealthChange = 20; 15 | 16 | public IGroup Group { get; } = new Group(typeof(HasHealthComponent)); 17 | private Random _random = new Random(); 18 | 19 | public IObservable ReactToGroup(IObservableGroup observableGroup) 20 | { return Observable.Interval(TimeSpan.FromMilliseconds(500)).Select(x => observableGroup); } 21 | 22 | public void Process(IEntity entity) 23 | { 24 | var healthComponent = entity.GetComponent(); 25 | 26 | var healthChange = CreateRandomHealthChange(); 27 | healthComponent.CurrentHealth += healthChange; 28 | 29 | if (healthComponent.CurrentHealth <= 0 || healthComponent.CurrentHealth > healthComponent.MaxHealth) 30 | { healthComponent.CurrentHealth = healthComponent.MaxHealth; } 31 | } 32 | 33 | public int CreateRandomHealthChange() 34 | { return _random.Next(-HealthChange, 0); } 35 | } 36 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/DataPipelinesExample/Components/PlayerStateComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Components; 3 | using LazyData.Attributes; 4 | 5 | namespace EcsRx.Examples.ExampleApps.DataPipelinesExample.Components 6 | { 7 | [Persist] 8 | public class PlayerStateComponent : IComponent 9 | { 10 | [PersistData] public int Level { get; set; } 11 | [PersistData] public string Name { get; set; } 12 | [PersistData] public TimeSpan PlayTime { get; set; } 13 | public string SomeFieldThatWontBePersisted { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/DataPipelinesExample/Events/SavePipelineEvent.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Examples.ExampleApps.DataPipelinesExample.Events 2 | { 3 | public class SavePipelineEvent 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/DataPipelinesExample/Modules/PipelineModule.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Infrastructure.Dependencies; 2 | using SystemsRx.Infrastructure.Extensions; 3 | using EcsRx.Examples.ExampleApps.DataPipelinesExample.Pipelines; 4 | using LazyJsonDeserializer = LazyData.Json.JsonDeserializer; 5 | using LazyJsonSerializer = LazyData.Json.JsonSerializer; 6 | using LazyData.Json.Handlers; 7 | using Persistity.Serializers.LazyData.Json; 8 | 9 | namespace EcsRx.Examples.ExampleApps.DataPipelinesExample.Modules 10 | { 11 | public class PipelineModule : IDependencyModule 12 | { 13 | public void Setup(IDependencyRegistry registry) 14 | { 15 | // By default only the binary stuff is loaded, but you can load json, yaml, bson etc 16 | registry.Bind(); 17 | registry.Bind(); 18 | registry.Bind(); 19 | registry.Bind(); 20 | registry.Bind(); 21 | 22 | // Register our custom pipeline using the json stuff above 23 | registry.Bind(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/DataPipelinesExample/Pipelines/PostJsonHttpPipeline.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Http; 3 | using EcsRx.Plugins.Persistence.Builders; 4 | using EcsRx.Plugins.Persistence.Pipelines; 5 | using Persistity.Endpoints.Http; 6 | using Persistity.Flow.Steps.Types; 7 | using Persistity.Serializers.LazyData.Json; 8 | 9 | namespace EcsRx.Examples.ExampleApps.DataPipelinesExample.Pipelines 10 | { 11 | public class PostJsonHttpPipeline : EcsRxBuiltPipeline 12 | { 13 | public PostJsonHttpPipeline(EcsRxPipelineBuilder pipelineBuilder) : base(pipelineBuilder) 14 | { } 15 | 16 | protected override IEnumerable BuildSteps(EcsRxPipelineBuilder builder) 17 | { 18 | return builder.StartFromInput() 19 | .SerializeWith(false) 20 | .ThenSendTo(new HttpSendEndpoint("https://postman-echo.com/post", HttpMethod.Post)) 21 | .BuildSteps(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/DataPipelinesExample/Systems/PlayerStateUpdaterGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Scheduling; 2 | using EcsRx.Entities; 3 | using EcsRx.Examples.ExampleApps.DataPipelinesExample.Components; 4 | using EcsRx.Extensions; 5 | using EcsRx.Groups; 6 | using EcsRx.Systems; 7 | 8 | namespace EcsRx.Examples.ExampleApps.DataPipelinesExample.Systems 9 | { 10 | public class PlayerStateUpdaterEntitySystem : IBasicEntitySystem 11 | { 12 | public IGroup Group { get; } = new Group(typeof(PlayerStateComponent)); 13 | 14 | public void Process(IEntity entity, ElapsedTime elapsedTime) 15 | { 16 | var playerState = entity.GetComponent(); 17 | playerState.PlayTime += elapsedTime.DeltaTime; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HealthExample/Blueprints/EnemyBlueprint.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.ReactiveData; 2 | using EcsRx.Blueprints; 3 | using EcsRx.Entities; 4 | using EcsRx.Examples.ExampleApps.HealthExample.Components; 5 | using EcsRx.Extensions; 6 | 7 | namespace EcsRx.Examples.ExampleApps.HealthExample.Blueprints 8 | { 9 | public class EnemyBlueprint : IBlueprint 10 | { 11 | public float Health { get; } 12 | 13 | public EnemyBlueprint(float health) 14 | { 15 | Health = health; 16 | } 17 | 18 | public void Apply(IEntity entity) 19 | { 20 | var healthComponent = new HealthComponent 21 | { 22 | Health = new ReactiveProperty(Health), 23 | MaxHealth = Health 24 | }; 25 | entity.AddComponents(healthComponent); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HealthExample/Components/HealthComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.ReactiveData; 3 | using EcsRx.Components; 4 | 5 | namespace EcsRx.Examples.ExampleApps.HealthExample.Components 6 | { 7 | public class HealthComponent : IComponent, IDisposable 8 | { 9 | public ReactiveProperty Health { get; set; } 10 | public float MaxHealth { get; set; } 11 | 12 | public void Dispose() 13 | { 14 | Health.Dispose(); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HealthExample/Events/EntityDamagedEvent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Examples.ExampleApps.HealthExample.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.HealthExample.Events 4 | { 5 | public class EntityDamagedEvent 6 | { 7 | public HealthComponent HealthComponent { get; } 8 | public float DamageApplied { get; } 9 | 10 | public EntityDamagedEvent(HealthComponent healthComponent, float damageApplied) 11 | { 12 | HealthComponent = healthComponent; 13 | DamageApplied = damageApplied; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HealthExample/HealthExampleApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Examples.Application; 4 | using EcsRx.Examples.ExampleApps.HealthExample.Blueprints; 5 | using EcsRx.Examples.ExampleApps.HealthExample.Components; 6 | using EcsRx.Examples.ExampleApps.HealthExample.Events; 7 | using EcsRx.Extensions; 8 | 9 | namespace EcsRx.Examples.ExampleApps.HealthExample 10 | { 11 | public class HealthExampleApplication : EcsRxConsoleApplication 12 | { 13 | private bool _quit; 14 | private IEntity _enemy; 15 | private readonly Random _random = new Random(); 16 | 17 | protected override void ApplicationStarted() 18 | { 19 | var defaultPool = EntityDatabase.GetCollection(); 20 | _enemy = defaultPool.CreateEntity(new EnemyBlueprint(100)); 21 | 22 | HandleInput(); 23 | } 24 | 25 | private void HandleInput() 26 | { 27 | var healthComponent = _enemy.GetComponent(); 28 | 29 | while (!_quit) 30 | { 31 | var keyPressed = Console.ReadKey(); 32 | if (keyPressed.Key == ConsoleKey.Spacebar) 33 | { 34 | var eventArg = new EntityDamagedEvent(healthComponent, _random.Next(5, 25)); 35 | EventSystem.Publish(eventArg); 36 | } 37 | else if (keyPressed.Key == ConsoleKey.Escape) 38 | { _quit = true; } 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HealthExample/Systems/TakeDamageSystem.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Systems.Conventional; 2 | using EcsRx.Examples.ExampleApps.HealthExample.Events; 3 | 4 | namespace EcsRx.Examples.ExampleApps.HealthExample.Systems 5 | { 6 | public class TakeDamageSystem : IReactToEventSystem 7 | { 8 | public void Process(EntityDamagedEvent eventData) 9 | { eventData.HealthComponent.Health.Value -= eventData.DamageApplied; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HelloWorldExample/Components/CanTalkComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.HelloWorldExample.Components 4 | { 5 | public class CanTalkComponent : IComponent 6 | { 7 | public string Message { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HelloWorldExample/HelloWorldExampleApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Examples.Application; 3 | using EcsRx.Examples.ExampleApps.HelloWorldExample.Components; 4 | using EcsRx.Extensions; 5 | 6 | namespace EcsRx.Examples.ExampleApps.HelloWorldExample 7 | { 8 | public class HelloWorldExampleApplication : EcsRxConsoleApplication 9 | { 10 | private bool _quit; 11 | 12 | protected override void ApplicationStarted() 13 | { 14 | var defaultPool = EntityDatabase.GetCollection(); 15 | var entity = defaultPool.CreateEntity(); 16 | 17 | var canTalkComponent = new CanTalkComponent {Message = "Hello world"}; 18 | entity.AddComponents(canTalkComponent); 19 | 20 | HandleInput(); 21 | } 22 | 23 | private void HandleInput() 24 | { 25 | while (!_quit) 26 | { 27 | var keyPressed = Console.ReadKey(); 28 | if (keyPressed.Key == ConsoleKey.Escape) 29 | { _quit = true; } 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/HelloWorldExample/Systems/TalkingGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Entities; 4 | using EcsRx.Examples.ExampleApps.HelloWorldExample.Components; 5 | using EcsRx.Extensions; 6 | using EcsRx.Groups; 7 | using EcsRx.Groups.Observable; 8 | using EcsRx.Systems; 9 | 10 | namespace EcsRx.Examples.ExampleApps.HelloWorldExample.Systems 11 | { 12 | public class TalkingGroupSystem : IReactToGroupSystem 13 | { 14 | public IGroup Group => new Group(typeof(CanTalkComponent)); 15 | 16 | public IObservable ReactToGroup(IObservableGroup observableGroup) 17 | { return Observable.Interval(TimeSpan.FromSeconds(2)).Select(x => observableGroup); } 18 | 19 | public void Process(IEntity entity) 20 | { 21 | var canTalkComponent = entity.GetComponent(); 22 | Console.WriteLine($"Entity says '{canTalkComponent.Message}' @ {DateTime.Now}"); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/LoadingEntityDatabase/Components/DummyComponent1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Components; 3 | 4 | namespace EcsRx.Examples.ExampleApps.LoadingEntityDatabase.Components 5 | { 6 | public class DummyComponent1 : IComponent 7 | { 8 | public int SomeNumber { get; set; } 9 | public string SomeString { get; set; } 10 | public DateTime SomeTime { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/LoadingEntityDatabase/Components/DummyComponent2.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using EcsRx.Components; 3 | 4 | namespace EcsRx.Examples.ExampleApps.LoadingEntityDatabase.Components 5 | { 6 | public class DummyComponent2 : IComponent 7 | { 8 | public Vector3 SomeVector { get; set; } 9 | public Quaternion SomeQuaternion { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/LoadingEntityDatabase/Modules/EnableNumericsModule.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Infrastructure.Dependencies; 2 | using SystemsRx.Infrastructure.Extensions; 3 | using LazyData.Binary.Handlers; 4 | using LazyData.Json.Handlers; 5 | using LazyData.Mappings.Types.Primitives.Checkers; 6 | using LazyData.Numerics.Checkers; 7 | using LazyData.Numerics.Handlers; 8 | 9 | namespace EcsRx.Examples.ExampleApps.LoadingEntityDatabase.Modules 10 | { 11 | public class EnableNumericsModule : IDependencyModule 12 | { 13 | public void Setup(IDependencyRegistry registry) 14 | { 15 | // For this one lets tell LazyData how to handle numeric types 16 | // For more info on this stuff look at the LazyData project docs 17 | registry.Bind(); 18 | 19 | // Tell it how to handle objects in System.Numerics in json world 20 | registry.Bind(); 21 | registry.Bind(); 22 | 23 | // Dont need this, but just showing how you load the numerics handler for binary formats 24 | registry.Bind(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/LoadingEntityDatabase/Modules/EntityDebugModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using SystemsRx.Infrastructure.Dependencies; 4 | using EcsRx.Plugins.Persistence.Extensions; 5 | using EcsRx.Plugins.Persistence.Pipelines; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Linq; 8 | using Persistity.Core; 9 | 10 | namespace EcsRx.Examples.ExampleApps.LoadingEntityDatabase.Modules 11 | { 12 | public class EntityDebugModule : IDependencyModule 13 | { 14 | public const string DebugPipeline = "DebugPipeline"; 15 | 16 | public void Setup(IDependencyRegistry registry) 17 | { 18 | // Make a new pipeline for showing json output 19 | registry.BuildPipeline(DebugPipeline, builder => builder 20 | // Fork from the 2nd step (serializer) on the existing JSON Saving Pipeline 21 | .ForkDataFrom(2) 22 | // Then spit out the json to the console in a nice way 23 | .ThenInvoke(WriteEntityData)); 24 | } 25 | 26 | private Task WriteEntityData(DataObject data) 27 | { 28 | var prettyText = JToken.Parse(data.AsString).ToString(Formatting.Indented); 29 | Console.WriteLine(prettyText); 30 | return Task.FromResult(data); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Performance/Components/SimpleReadComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.Performance.Components 4 | { 5 | public class SimpleReadComponent : IComponent 6 | { 7 | public float StartingValue { get; set; } = 100.0f; 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Performance/Components/SimpleWriteComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.Performance.Components 4 | { 5 | public class SimpleWriteComponent : IComponent 6 | { 7 | public float WrittenValue { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Performance/Extensions/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace EcsRx.Examples.ExampleApps.Performance.Extensions 6 | { 7 | public static class IEnumerableExtensions 8 | { 9 | private static readonly Random _random = new Random(); 10 | 11 | public static IEnumerable Shuffle(this IEnumerable list) 12 | { 13 | var shuffled = list.ToArray(); 14 | var n = shuffled.Length; 15 | while (n > 1) { 16 | n--; 17 | var k = _random.Next(n + 1); 18 | var value = shuffled[k]; 19 | shuffled[k] = shuffled[n]; 20 | shuffled[n] = value; 21 | } 22 | return shuffled; 23 | } 24 | 25 | public static IEnumerable Random(this IEnumerable list, int amount) 26 | { return list.Shuffle().Take(amount); } 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Performance/Helper/RandomGroupFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using EcsRx.Examples.ExampleApps.Performance.Components.Specific; 5 | using EcsRx.Groups; 6 | 7 | namespace EcsRx.Examples.ExampleApps.Performance.Helper 8 | { 9 | public class RandomGroupFactory 10 | { 11 | public IEnumerable GetComponentTypes => _componentTypes; 12 | private List _componentTypes; 13 | 14 | public RandomGroupFactory() 15 | { 16 | PopulateComponentList(); 17 | } 18 | 19 | private void PopulateComponentList() 20 | { 21 | var componentNamespace = typeof(Component1).Namespace; 22 | var componentTypes = typeof(Component1).Assembly.GetTypes().Where(x => x.Namespace == componentNamespace); 23 | _componentTypes = componentTypes.ToList(); 24 | } 25 | 26 | public IEnumerable CreateTestGroups(int cycles = 5) 27 | { 28 | for (var i = 1; i < cycles; i++) 29 | { 30 | for (var j = 0; j < _componentTypes.Count; j++) 31 | { 32 | yield return new Group(_componentTypes.Skip(i).Take(j).ToArray()); 33 | } 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Performance/MakingLotsOfEntitiesApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using SystemsRx.Infrastructure.Extensions; 4 | using SystemsRx.Systems; 5 | using EcsRx.Examples.Application; 6 | using EcsRx.Examples.ExampleApps.Performance.Components; 7 | using EcsRx.Examples.ExampleApps.Performance.Systems; 8 | using EcsRx.Extensions; 9 | using EcsRx.Systems; 10 | 11 | namespace EcsRx.Examples.ExampleApps.Performance 12 | { 13 | public class MakingLotsOfEntitiesApplication : EcsRxConsoleApplication 14 | { 15 | private static readonly int EntityCount = 100000; 16 | 17 | protected override void BindSystems() 18 | { 19 | DependencyRegistry.Bind(); 20 | } 21 | 22 | protected override void ApplicationStarted() 23 | { 24 | var collection = EntityDatabase.GetCollection(); 25 | 26 | 27 | var stopwatch = new Stopwatch(); 28 | stopwatch.Start(); 29 | for (var i = 0; i < EntityCount; i++) 30 | { 31 | var entity = collection.CreateEntity(); 32 | entity.AddComponents(new SimpleReadComponent(), new SimpleWriteComponent()); 33 | } 34 | stopwatch.Stop(); 35 | Console.WriteLine($"Finished In: {stopwatch.ElapsedMilliseconds}ms"); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Performance/Systems/ExampleBatchedSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using SystemsRx.Threading; 4 | using EcsRx.Collections; 5 | using EcsRx.Components.Database; 6 | using EcsRx.Components.Lookups; 7 | using EcsRx.Entities; 8 | using EcsRx.Examples.ExampleApps.Performance.Components; 9 | using EcsRx.Plugins.Batching.Factories; 10 | using EcsRx.Plugins.Batching.Systems; 11 | 12 | namespace EcsRx.Examples.ExampleApps.Performance.Systems 13 | { 14 | public class ExampleBatchedSystem : ReferenceBatchedSystem 15 | { 16 | public ExampleBatchedSystem(IComponentDatabase componentDatabase, IComponentTypeLookup componentTypeLookup, 17 | IReferenceBatchBuilderFactory batchBuilderFactory, IThreadHandler threadHandler, IObservableGroupManager observableGroupManager) 18 | : base(componentDatabase, componentTypeLookup, batchBuilderFactory, threadHandler, observableGroupManager) 19 | {} 20 | 21 | protected override IObservable ReactWhen() 22 | { return Observable.Never(); } 23 | 24 | // This shows that every time the group changes, it should throttle (actually debounce) and run after 10ms 25 | protected override IObservable ProcessGroupSubscription(IObservable groupChange) 26 | { return groupChange.Throttle(TimeSpan.FromMilliseconds(10)); } 27 | 28 | protected override void Process(int EntityId, SimpleReadComponent component1, SimpleWriteComponent component2) 29 | {} 30 | } 31 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Performance/Systems/ExampleReactToGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using System.Threading; 4 | using EcsRx.Entities; 5 | using EcsRx.Examples.ExampleApps.Performance.Components; 6 | using EcsRx.Extensions; 7 | using EcsRx.Groups; 8 | using EcsRx.Groups.Observable; 9 | using EcsRx.Systems; 10 | 11 | namespace EcsRx.Examples.ExampleApps.Performance.Systems 12 | { 13 | public class ExampleReactToGroupSystem : IReactToGroupSystem 14 | { 15 | public IGroup Group { get; } = new Group(typeof(SimpleReadComponent), typeof(SimpleWriteComponent)); 16 | 17 | public IObservable ReactToGroup(IObservableGroup observableGroup) 18 | { return Observable.Interval(TimeSpan.FromSeconds(1)).StartWith().Select(x => observableGroup); } 19 | 20 | public void Process(IEntity entity) 21 | { 22 | var readComponent = entity.GetComponent(); 23 | var writeComponent = entity.GetComponent(); 24 | writeComponent.WrittenValue = readComponent.StartingValue; 25 | Thread.Sleep(1); // Just to pretend there is something complex happening 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/Batches/CustomClassBatch.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Examples.ExampleApps.Playground.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.Playground.Batches 4 | { 5 | public struct CustomClassBatch 6 | { 7 | public int EntityId; 8 | public ClassComponent Basic; 9 | public ClassComponent2 Basic2; 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/Batches/CustomStructBatch.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using EcsRx.Examples.ExampleApps.Playground.Components; 3 | 4 | namespace EcsRx.Examples.ExampleApps.Playground.Batches 5 | { 6 | [StructLayout(LayoutKind.Sequential)] 7 | public struct CustomStructBatch 8 | { 9 | public int EntityId; 10 | public StructComponent Basic; 11 | public StructComponent2 Basic2; 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/Batches/CustomUnsafeStructBatch.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using EcsRx.Examples.ExampleApps.Playground.Components; 3 | 4 | namespace EcsRx.Examples.ExampleApps.Playground.Batches 5 | { 6 | [StructLayout(LayoutKind.Sequential)] 7 | public struct CustomUnsafeStructBatch 8 | { 9 | public int EntityId; 10 | public StructComponent Basic; 11 | public StructComponent2 Basic2; 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/ClassBased/Class1Application.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using EcsRx.Entities; 3 | using EcsRx.Examples.ExampleApps.Playground.Components; 4 | using EcsRx.Extensions; 5 | 6 | namespace EcsRx.Examples.ExampleApps.Playground.ClassBased 7 | { 8 | public class Class1Application : BasicLoopApplication 9 | { 10 | protected override string Description { get; } = 11 | "Simplest possible approach, no pre allocation, using generics"; 12 | 13 | protected override void SetupEntity(IEntity entity) 14 | { 15 | entity.AddComponent(); 16 | entity.AddComponent(); 17 | } 18 | 19 | protected override void RunProcess() 20 | { 21 | foreach (var entity in _collection) 22 | { 23 | var basicComponent = entity.GetComponent(); 24 | basicComponent.Position += Vector3.One; 25 | basicComponent.Something += 10; 26 | 27 | var basicComponent2 = entity.GetComponent(); 28 | basicComponent2.Value += 10; 29 | basicComponent2.IsTrue = true; 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/ClassBased/Class2Application.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using EcsRx.Entities; 3 | using EcsRx.Examples.ExampleApps.Playground.Components; 4 | using EcsRx.Extensions; 5 | 6 | namespace EcsRx.Examples.ExampleApps.Playground.ClassBased 7 | { 8 | public class Class2Application : BasicLoopApplication 9 | { 10 | protected override void SetupEntities() 11 | { 12 | _componentDatabase.PreAllocateComponents(ClassComponent1TypeId, EntityCount); 13 | _componentDatabase.PreAllocateComponents(ClassComponent2TypeId, EntityCount); 14 | base.SetupEntities(); 15 | } 16 | 17 | protected override string Description { get; } = 18 | "Improved by pre-allocating components and using component type ids"; 19 | 20 | protected override void SetupEntity(IEntity entity) 21 | { 22 | entity.AddComponent(); 23 | entity.AddComponent(); 24 | } 25 | 26 | protected override void RunProcess() 27 | { 28 | for (var i = _collection.Count - 1; i >= 0; i--) 29 | { 30 | var entity = _collection[i]; 31 | var basicComponent = entity.GetComponent(ClassComponent1TypeId); 32 | basicComponent.Position += Vector3.One; 33 | basicComponent.Something += 10; 34 | 35 | var basicComponent2 = entity.GetComponent(ClassComponent2TypeId); 36 | basicComponent2.Value += 10; 37 | basicComponent2.IsTrue = true; 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/Components/ClassComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using EcsRx.Components; 3 | 4 | namespace EcsRx.Examples.ExampleApps.Playground.Components 5 | { 6 | public class ClassComponent : IComponent 7 | { 8 | public Vector3 Position { get; set; } 9 | public float Something { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/Components/ClassComponent2.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Examples.ExampleApps.Playground.Components 4 | { 5 | public class ClassComponent2 : IComponent 6 | { 7 | public bool IsTrue { get; set; } 8 | public int Value { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/Components/StructComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.InteropServices; 3 | using EcsRx.Components; 4 | 5 | namespace EcsRx.Examples.ExampleApps.Playground.Components 6 | { 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct StructComponent : IComponent 9 | { 10 | public Vector3 Position { get; set; } 11 | public float Something { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/Components/StructComponent2.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using EcsRx.Components; 3 | 4 | namespace EcsRx.Examples.ExampleApps.Playground.Components 5 | { 6 | [StructLayout(LayoutKind.Sequential)] 7 | public struct StructComponent2 : IComponent 8 | { 9 | public byte IsTrue; 10 | public int Value; 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/StructBased/Struct1Application.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using EcsRx.Entities; 3 | using EcsRx.Examples.ExampleApps.Playground.Components; 4 | 5 | namespace EcsRx.Examples.ExampleApps.Playground.StructBased 6 | { 7 | /// 8 | /// 9 | /// 10 | public class Struct1Application : BasicLoopApplication 11 | { 12 | protected override string Description { get; } = "Simplest possible approach but with structs"; 13 | 14 | protected override void SetupEntity(IEntity entity) 15 | { 16 | entity.AddComponent(StructComponent1TypeId); 17 | entity.AddComponent(StructComponent2TypeId); 18 | } 19 | 20 | protected override void RunProcess() 21 | { 22 | foreach (var entity in _collection) 23 | { 24 | ref var basicComponent = ref entity.GetComponent(StructComponent1TypeId); 25 | basicComponent.Position += Vector3.One; 26 | basicComponent.Something += 10; 27 | 28 | ref var basicComponent2 = ref entity.GetComponent(StructComponent2TypeId); 29 | basicComponent2.Value += 10; 30 | basicComponent2.IsTrue = 1; 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/EcsRx.Examples/ExampleApps/Playground/StructBased/Struct2Application.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using EcsRx.Entities; 3 | using EcsRx.Examples.ExampleApps.Playground.Components; 4 | 5 | namespace EcsRx.Examples.ExampleApps.Playground.StructBased 6 | { 7 | public class Struct2Application : BasicLoopApplication 8 | { 9 | protected override void SetupEntities() 10 | { 11 | _componentDatabase.PreAllocateComponents(StructComponent1TypeId, EntityCount); 12 | _componentDatabase.PreAllocateComponents(StructComponent2TypeId, EntityCount); 13 | base.SetupEntities(); 14 | } 15 | 16 | protected override string Description { get; } = 17 | "Improved by pre-allocating components and using component type ids with structs"; 18 | 19 | protected override void SetupEntity(IEntity entity) 20 | { 21 | entity.AddComponent(StructComponent1TypeId); 22 | entity.AddComponent(StructComponent2TypeId); 23 | } 24 | 25 | protected override void RunProcess() 26 | { 27 | for (var i = _collection.Count - 1; i >= 0; i--) 28 | { 29 | var entity = _collection[i]; 30 | ref var basicComponent = ref entity.GetComponent(StructComponent1TypeId); 31 | basicComponent.Position += Vector3.One; 32 | basicComponent.Something += 10; 33 | 34 | ref var basicComponent2 = ref entity.GetComponent(StructComponent2TypeId); 35 | basicComponent2.Value += 10; 36 | basicComponent2.IsTrue = 1; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/EcsRx.Examples/Extensions/IObservableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | 4 | namespace EcsRx.Examples.Extensions 5 | { 6 | public class ValueChanges 7 | { 8 | public T PreviousValue { get; } 9 | public T CurrentValue { get; } 10 | 11 | public ValueChanges(T previousValue, T currentValue) 12 | { 13 | PreviousValue = previousValue; 14 | CurrentValue = currentValue; 15 | } 16 | } 17 | 18 | public static class IObservableExtensions 19 | { 20 | public static IObservable> WithValueChange(this IObservable source) 21 | { 22 | return source.Scan(new ValueChanges(default(T), default(T)), 23 | (acc, current) => new ValueChanges(acc.CurrentValue, current)); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/EcsRx.Infrastructure/EcsRx.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 0.0.0 4 | netstandard2.1 5 | EcsRx.Infrastructure 6 | Grofit (LP) 7 | https://github.com/ecsrx/ecsrx/blob/master/LICENSE 8 | https://github.com/ecsrx/ecsrx 9 | A set of convention based classes to speed up the setup of projects using EcsRx 10 | ecs rx reactive patterns ioc game-development view-separation xna monogame unity 11 | 8 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/EcsRx.Infrastructure/EcsRxApplication.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Infrastructure; 2 | using SystemsRx.Infrastructure.Extensions; 3 | using EcsRx.Collections; 4 | using EcsRx.Collections.Database; 5 | using EcsRx.Infrastructure.Modules; 6 | 7 | namespace EcsRx.Infrastructure 8 | { 9 | public abstract class EcsRxApplication : SystemsRxApplication, IEcsRxApplication 10 | { 11 | public IEntityDatabase EntityDatabase { get; private set; } 12 | public IObservableGroupManager ObservableGroupManager { get; private set; } 13 | 14 | /// 15 | /// Load any modules that your application needs 16 | /// 17 | /// 18 | /// If you wish to use the default setup call through to base, if you wish to stop the default framework 19 | /// modules loading then do not call base and register your own internal framework module. 20 | /// 21 | protected override void LoadModules() 22 | { 23 | base.LoadModules(); 24 | DependencyRegistry.LoadModule(new EcsRxInfrastructureModule()); 25 | } 26 | 27 | /// 28 | /// Resolve any dependencies the application needs 29 | /// 30 | /// By default it will setup IEntityDatabase, IObservableGroupManager and base class dependencies 31 | protected override void ResolveApplicationDependencies() 32 | { 33 | base.ResolveApplicationDependencies(); 34 | EntityDatabase = DependencyResolver.Resolve(); 35 | ObservableGroupManager = DependencyResolver.Resolve(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/EcsRx.Infrastructure/Extensions/IDependencyContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Infrastructure.Dependencies; 3 | using SystemsRx.Infrastructure.Extensions; 4 | using EcsRx.Collections; 5 | using EcsRx.Groups; 6 | using EcsRx.Groups.Observable; 7 | 8 | namespace EcsRx.Infrastructure.Extensions 9 | { 10 | public static class IDependencyContainerExtensions 11 | { 12 | /// 13 | /// Resolves an observable group 14 | /// 15 | /// The container to action on 16 | /// The group to observe 17 | /// The observable group 18 | public static IObservableGroup ResolveObservableGroup(this IDependencyResolver resolver, IGroup group) 19 | { 20 | var collectionManager = resolver.Resolve(); 21 | return collectionManager.GetObservableGroup(group); 22 | } 23 | 24 | /// 25 | /// Resolves an observable group 26 | /// 27 | /// The container to action on 28 | /// The required components for the group to observe 29 | /// 30 | public static IObservableGroup ResolveObservableGroup(this IDependencyResolver resolver, params Type[] componentTypes) 31 | { 32 | var collectionManager = resolver.Resolve(); 33 | var group = new Group(componentTypes); 34 | return collectionManager.GetObservableGroup(group); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/EcsRx.Infrastructure/Extensions/IEcsRxApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using EcsRx.Systems; 4 | using SystemsRx.Extensions; 5 | using SystemsRx.Infrastructure.Extensions; 6 | using SystemsRx.Systems; 7 | 8 | namespace EcsRx.Infrastructure.Extensions 9 | { 10 | public static class IEcsRxApplicationExtensions 11 | { 12 | /// 13 | /// Resolve all systems which have been bound in the order they need to be triggered 14 | /// 15 | /// The application to act on 16 | /// The ordering here will be Setup, Anything else 17 | public static IEnumerable GetAllBoundReactiveSystems(this IEcsRxApplication application) 18 | { 19 | var allSystems = application.DependencyResolver.ResolveAll(); 20 | 21 | return allSystems 22 | .OrderByDescending(x => x is ISetupSystem) 23 | .ThenByPriority(); 24 | } 25 | 26 | /// 27 | /// Resolve all systems which have been bound and register them in order with the systems executor 28 | /// 29 | /// The application to act on 30 | /// The ordering here will be Setup, Anything else 31 | public static void StartAllBoundReactiveSystems(this IEcsRxApplication application) 32 | { 33 | var orderedSystems = GetAllBoundReactiveSystems(application); 34 | orderedSystems.ForEachRun(application.SystemExecutor.AddSystem); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/EcsRx.Infrastructure/IEcsRxApplication.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Infrastructure; 2 | using EcsRx.Collections; 3 | using EcsRx.Collections.Database; 4 | 5 | namespace EcsRx.Infrastructure 6 | { 7 | public interface IEcsRxApplication : ISystemsRxApplication 8 | { 9 | /// 10 | /// The entity database, allows you to create and manage entity collections 11 | /// 12 | IEntityDatabase EntityDatabase { get; } 13 | 14 | /// 15 | /// The observable group manager, allows you to get observable groups 16 | /// 17 | IObservableGroupManager ObservableGroupManager { get; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Batching/Accessors/AccessorToken.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Groups.Observable; 2 | 3 | namespace EcsRx.Plugins.Batching.Accessors 4 | { 5 | public class AccessorToken 6 | { 7 | public int[] ComponentTypeIds { get; } 8 | public IObservableGroup ObservableGroup { get; } 9 | 10 | public AccessorToken(int[] componentTypeIds, IObservableGroup observableGroup) 11 | { 12 | ComponentTypeIds = componentTypeIds; 13 | ObservableGroup = observableGroup; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Batching/BatchPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SystemsRx.Infrastructure.Dependencies; 4 | using SystemsRx.Infrastructure.Extensions; 5 | using SystemsRx.Infrastructure.Plugins; 6 | using SystemsRx.Systems; 7 | using EcsRx.Plugins.Batching.Accessors; 8 | using EcsRx.Plugins.Batching.Factories; 9 | 10 | namespace EcsRx.Plugins.Batching 11 | { 12 | public class BatchPlugin : ISystemsRxPlugin 13 | { 14 | public string Name => "Batching"; 15 | public Version Version { get; } = new Version("1.0.0"); 16 | 17 | public void SetupDependencies(IDependencyRegistry registry) 18 | { 19 | registry.Bind(x => x.AsSingleton()); 20 | registry.Bind(x => x.AsSingleton()); 21 | registry.Bind(x => x.AsSingleton()); 22 | } 23 | 24 | public IEnumerable GetSystemsForRegistration(IDependencyResolver resolver) => Array.Empty(); 25 | } 26 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Batching/EcsRx.Plugins.Batching.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 0.0.0 5 | netstandard2.1 6 | EcsRx.Plugins.Batching 7 | Grofit (LP) 8 | https://github.com/ecsrx/ecsrx/blob/master/LICENSE 9 | https://github.com/ecsrx/ecsrx 10 | EcsRx plugin to allow batching of components in systems 11 | ecs rx reactive patterns ioc game-development xna monogame unity 12 | latest 13 | true 14 | 8 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Batching/Factories/IBatchBuilderFactory.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | using EcsRx.Plugins.Batching.Builders; 3 | 4 | namespace EcsRx.Plugins.Batching.Factories 5 | { 6 | public interface IBatchBuilderFactory 7 | { 8 | IBatchBuilder Create() 9 | where T1 : unmanaged, IComponent 10 | where T2 : unmanaged, IComponent; 11 | 12 | IBatchBuilder Create() 13 | where T1 : unmanaged, IComponent 14 | where T2 : unmanaged, IComponent 15 | where T3 : unmanaged, IComponent; 16 | 17 | IBatchBuilder Create() 18 | where T1 : unmanaged, IComponent 19 | where T2 : unmanaged, IComponent 20 | where T3 : unmanaged, IComponent 21 | where T4 : unmanaged, IComponent; 22 | 23 | IBatchBuilder Create() 24 | where T1 : unmanaged, IComponent 25 | where T2 : unmanaged, IComponent 26 | where T3 : unmanaged, IComponent 27 | where T4 : unmanaged, IComponent 28 | where T5 : unmanaged, IComponent; 29 | 30 | IBatchBuilder Create() 31 | where T1 : unmanaged, IComponent 32 | where T2 : unmanaged, IComponent 33 | where T3 : unmanaged, IComponent 34 | where T4 : unmanaged, IComponent 35 | where T5 : unmanaged, IComponent 36 | where T6 : unmanaged, IComponent; 37 | } 38 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Batching/Factories/IReferenceBatchBuilderFactory.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | using EcsRx.Plugins.Batching.Builders; 3 | 4 | namespace EcsRx.Plugins.Batching.Factories 5 | { 6 | public interface IReferenceBatchBuilderFactory 7 | { 8 | IReferenceBatchBuilder Create() 9 | where T1 : class, IComponent 10 | where T2 : class, IComponent; 11 | 12 | IReferenceBatchBuilder Create() 13 | where T1 : class, IComponent 14 | where T2 : class, IComponent 15 | where T3 : class, IComponent; 16 | 17 | IReferenceBatchBuilder Create() 18 | where T1 : class, IComponent 19 | where T2 : class, IComponent 20 | where T3 : class, IComponent 21 | where T4 : class, IComponent; 22 | 23 | IReferenceBatchBuilder Create() 24 | where T1 : class, IComponent 25 | where T2 : class, IComponent 26 | where T3 : class, IComponent 27 | where T4 : class, IComponent 28 | where T5 : class, IComponent; 29 | 30 | IReferenceBatchBuilder Create() 31 | where T1 : class, IComponent 32 | where T2 : class, IComponent 33 | where T3 : class, IComponent 34 | where T4 : class, IComponent 35 | where T5 : class, IComponent 36 | where T6 : class, IComponent; 37 | } 38 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.GroupBinding/Attributes/FromComponentsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Groups; 3 | 4 | namespace EcsRx.Plugins.GroupBinding.Attributes 5 | { 6 | /// 7 | /// Will attempt to auto populate an ObservableGroup with a provided required components 8 | /// 9 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 10 | public class FromComponentsAttribute : Attribute 11 | { 12 | public IGroup Group { get; } 13 | 14 | public FromComponentsAttribute(params Type[] requiredComponents) 15 | { Group = new Group(requiredComponents); } 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.GroupBinding/Attributes/FromGroupAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Groups; 3 | 4 | namespace EcsRx.Plugins.GroupBinding.Attributes 5 | { 6 | /// 7 | /// Will attempt to auto populate an ObservableGroup with a provided group or IGroupSystem Group property 8 | /// 9 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 10 | public class FromGroupAttribute : Attribute 11 | { 12 | public IGroup Group { get; } 13 | 14 | public FromGroupAttribute(Type group = null) 15 | { Group = group == null ? null : (IGroup)Activator.CreateInstance(group); } 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.GroupBinding/EcsRx.Plugins.GroupBinding.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.1 6 | EcsRx.Plugins.GroupBinding 7 | Grofit (LP) 8 | https://github.com/ecsrx/ecsrx/blob/master/LICENSE 9 | https://github.com/ecsrx/ecsrx 10 | EcsRx plugin to allow auto resolving of IObservableGroup properties or fields 11 | ecs rx reactive patterns ioc game-development xna monogame unity 12 | 8 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/EcsRx.Plugins.GroupBinding/Exceptions/MissingGroupSystemInterfaceException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using SystemsRx.Systems; 4 | 5 | namespace EcsRx.Plugins.GroupBinding.Exceptions 6 | { 7 | public class MissingGroupSystemInterfaceException : Exception 8 | { 9 | public ISystem System { get; } 10 | public MemberInfo Member { get; } 11 | 12 | public MissingGroupSystemInterfaceException(ISystem system, MemberInfo member) 13 | : base($"{member.Name} GroupFrom attribute cannot find an IGroupSystem on {system.GetType().Name}") 14 | { 15 | System = system; 16 | Member = member; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.GroupBinding/GroupBindingsPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SystemsRx.Executor.Handlers; 4 | using SystemsRx.Infrastructure.Dependencies; 5 | using SystemsRx.Infrastructure.Extensions; 6 | using SystemsRx.Infrastructure.Plugins; 7 | using SystemsRx.Systems; 8 | using EcsRx.Plugins.GroupBinding.Systems.Handlers; 9 | 10 | namespace EcsRx.Plugins.GroupBinding 11 | { 12 | public class GroupBindingsPlugin : ISystemsRxPlugin 13 | { 14 | public string Name => "Group Bindings"; 15 | public Version Version { get; } = new Version("1.0.0"); 16 | 17 | public void SetupDependencies(IDependencyRegistry registry) 18 | { registry.Bind(); } 19 | 20 | public IEnumerable GetSystemsForRegistration(IDependencyResolver resolver) => Array.Empty(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.GroupBinding/Groups/GroupWithAffinity.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Groups; 2 | 3 | namespace EcsRx.Plugins.GroupBinding.Groups 4 | { 5 | public struct GroupWithAffinity 6 | { 7 | public static GroupWithAffinity Default { get; } = new GroupWithAffinity(); 8 | 9 | public IGroup Group { get; } 10 | public int[] CollectionIds { get; } 11 | 12 | public GroupWithAffinity(IGroup group, int[] collectionIds) 13 | { 14 | Group = group; 15 | CollectionIds = collectionIds; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Data/EntityCollectionData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EcsRx.Plugins.Persistence.Data 4 | { 5 | public class EntityCollectionData 6 | { 7 | public int CollectionId { get; set; } 8 | public List Entities { get; set; } 9 | 10 | public EntityCollectionData() 11 | { 12 | Entities = new List(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Data/EntityData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EcsRx.Components; 3 | 4 | namespace EcsRx.Plugins.Persistence.Data 5 | { 6 | public class EntityData 7 | { 8 | public int EntityId { get; set; } 9 | public List Components { get; set; } 10 | 11 | public EntityData() 12 | { 13 | Components = new List(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Data/EntityDatabaseData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EcsRx.Plugins.Persistence.Data 4 | { 5 | public class EntityDatabaseData 6 | { 7 | public List EntityCollections { get; set; } 8 | public string Version { get; set; } 9 | 10 | public EntityDatabaseData() 11 | { 12 | EntityCollections = new List(); 13 | Version = "1.0.0"; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/EcsRx.Plugins.Persistence.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 0.0.0 5 | netstandard2.1 6 | EcsRx.Plugins.Persistence 7 | Grofit (LP) 8 | https://github.com/ecsrx/ecsrx/blob/master/LICENSE 9 | https://github.com/ecsrx/ecsrx 10 | A suite of persistence related features and helpers to allow you to make complex data pipelines, as well as saving/loading entity databases 11 | ecs rx reactive patterns ioc game-development xna monogame unity 12 | 8 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/PersistencePlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SystemsRx.Infrastructure.Dependencies; 4 | using SystemsRx.Infrastructure.Extensions; 5 | using SystemsRx.Infrastructure.Plugins; 6 | using SystemsRx.Systems; 7 | using EcsRx.Plugins.Persistence.Modules; 8 | 9 | namespace EcsRx.Plugins.Persistence 10 | { 11 | public class PersistencePlugin : ISystemsRxPlugin 12 | { 13 | public string Name => "Persistence Plugin"; 14 | public Version Version { get; } = new Version("1.0.0"); 15 | 16 | public void SetupDependencies(IDependencyRegistry registry) 17 | { 18 | registry.LoadModule(); 19 | registry.LoadModule(); 20 | } 21 | 22 | public IEnumerable GetSystemsForRegistration(IDependencyResolver resolver) => Array.Empty(); 23 | } 24 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Pipelines/DefaultLoadEntityDatabasePipeline.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using EcsRx.Collections.Database; 4 | using EcsRx.Plugins.Persistence.Builders; 5 | using EcsRx.Plugins.Persistence.Data; 6 | using EcsRx.Plugins.Persistence.Transformers; 7 | using Persistity.Core.Serialization; 8 | using Persistity.Endpoints; 9 | using Persistity.Flow.Pipelines; 10 | using Persistity.Flow.Steps.Types; 11 | 12 | namespace EcsRx.Plugins.Persistence.Pipelines 13 | { 14 | public class DefaultLoadEntityDatabasePipeline : FlowPipeline, ILoadEntityDatabasePipeline 15 | { 16 | public IDeserializer Deserializer { get; } 17 | public IFromEntityDatabaseDataTransformer DataTransformer { get; } 18 | public IReceiveDataEndpoint Endpoint { get; } 19 | 20 | public DefaultLoadEntityDatabasePipeline(EcsRxPipelineBuilder pipelineBuilder, IDeserializer deserializer, IFromEntityDatabaseDataTransformer dataTransformer, IReceiveDataEndpoint endpoint) 21 | { 22 | Deserializer = deserializer; 23 | DataTransformer = dataTransformer; 24 | Endpoint = endpoint; 25 | 26 | Steps = BuildSteps(pipelineBuilder); 27 | } 28 | 29 | public async Task Execute() 30 | { return (IEntityDatabase) await Execute(null).ConfigureAwait(false); } 31 | 32 | protected IEnumerable BuildSteps(EcsRxPipelineBuilder builder) 33 | { 34 | return builder 35 | .StartFrom(Endpoint) 36 | .DeserializeWith(Deserializer, typeof(EntityDatabaseData)) 37 | .TransformWith(DataTransformer) 38 | .BuildSteps(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Pipelines/DefaultSaveEntityDatabasePipeline.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using EcsRx.Collections.Database; 4 | using EcsRx.Plugins.Persistence.Builders; 5 | using EcsRx.Plugins.Persistence.Transformers; 6 | using Persistity.Core.Serialization; 7 | using Persistity.Endpoints; 8 | using Persistity.Flow.Pipelines; 9 | using Persistity.Flow.Steps.Types; 10 | 11 | namespace EcsRx.Plugins.Persistence.Pipelines 12 | { 13 | public class DefaultSaveEntityDatabasePipeline : FlowPipeline, ISaveEntityDatabasePipeline 14 | { 15 | public ISerializer Serializer { get; } 16 | public IToEntityDatabaseDataTransformer DataTransformer { get; } 17 | public ISendDataEndpoint Endpoint { get; } 18 | 19 | public DefaultSaveEntityDatabasePipeline(EcsRxPipelineBuilder pipelineBuilder, ISerializer serializer, IToEntityDatabaseDataTransformer dataTransformer, ISendDataEndpoint endpoint) 20 | { 21 | Serializer = serializer; 22 | DataTransformer = dataTransformer; 23 | Endpoint = endpoint; 24 | 25 | Steps = BuildSteps(pipelineBuilder); 26 | } 27 | 28 | public Task Execute(IEntityDatabase entityDatabase) 29 | { return Execute(entityDatabase, null); } 30 | 31 | protected IEnumerable BuildSteps(EcsRxPipelineBuilder builder) 32 | { 33 | return builder 34 | .StartFromInput() 35 | .TransformWith(DataTransformer) 36 | .SerializeWith(Serializer) 37 | .ThenSendTo(Endpoint) 38 | .BuildSteps(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Pipelines/EcsRxBuiltPipeline.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EcsRx.Plugins.Persistence.Builders; 3 | using Persistity.Flow.Pipelines; 4 | using Persistity.Flow.Steps.Types; 5 | 6 | namespace EcsRx.Plugins.Persistence.Pipelines 7 | { 8 | public abstract class EcsRxBuiltPipeline : FlowPipeline 9 | { 10 | public EcsRxBuiltPipeline(EcsRxPipelineBuilder pipelineBuilder) 11 | { 12 | Steps = BuildSteps(pipelineBuilder); 13 | } 14 | 15 | protected abstract IEnumerable BuildSteps(EcsRxPipelineBuilder builder); 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Pipelines/ILoadEntityDatabasePipeline.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using EcsRx.Collections.Database; 3 | using Persistity.Flow.Pipelines; 4 | 5 | namespace EcsRx.Plugins.Persistence.Pipelines 6 | { 7 | public interface ILoadEntityDatabasePipeline : IFlowPipeline 8 | { 9 | Task Execute(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Pipelines/ISaveEntityDatabasePipeline.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using EcsRx.Collections.Database; 3 | using Persistity.Flow.Pipelines; 4 | 5 | namespace EcsRx.Plugins.Persistence.Pipelines 6 | { 7 | public interface ISaveEntityDatabasePipeline : IFlowPipeline 8 | { 9 | Task Execute(IEntityDatabase database); 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/FromEntityCollectionDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using SystemsRx.Extensions; 3 | using EcsRx.Collections.Entity; 4 | using EcsRx.Entities; 5 | using EcsRx.Extensions; 6 | using EcsRx.Plugins.Persistence.Data; 7 | 8 | namespace EcsRx.Plugins.Persistence.Transformers 9 | { 10 | public class FromEntityCollectionDataTransformer : IFromEntityCollectionDataTransformer 11 | { 12 | public IFromEntityDataTransformer EntityDataTransformer { get; } 13 | public IEntityCollectionFactory EntityCollectionFactory { get; } 14 | 15 | public FromEntityCollectionDataTransformer(IFromEntityDataTransformer entityDataTransformer, IEntityCollectionFactory entityCollectionFactory) 16 | { 17 | EntityDataTransformer = entityDataTransformer; 18 | EntityCollectionFactory = entityCollectionFactory; 19 | } 20 | 21 | public object Transform(object converted) 22 | { 23 | var collectionData = (EntityCollectionData) converted; 24 | var collection = EntityCollectionFactory.Create(collectionData.CollectionId); 25 | var entities = collectionData.Entities 26 | .Select(EntityDataTransformer.Transform) 27 | .Cast(); 28 | 29 | entities.ForEachRun(collection.AddEntity); 30 | return collection; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/FromEntityDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using EcsRx.Plugins.Persistence.Data; 3 | 4 | namespace EcsRx.Plugins.Persistence.Transformers 5 | { 6 | public class FromEntityDataTransformer : IFromEntityDataTransformer 7 | { 8 | public IEntityFactory EntityFactory { get; } 9 | 10 | public FromEntityDataTransformer(IEntityFactory entityFactory) 11 | { 12 | EntityFactory = entityFactory; 13 | } 14 | 15 | public object Transform(object converted) 16 | { 17 | var entityData = (EntityData) converted; 18 | var entity = EntityFactory.Create(entityData.EntityId); 19 | entity.AddComponents(entityData.Components.ToArray()); 20 | return entity; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/FromEntityDatabaseDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using SystemsRx.Extensions; 3 | using EcsRx.Collections.Database; 4 | using EcsRx.Collections.Entity; 5 | using EcsRx.Plugins.Persistence.Data; 6 | 7 | namespace EcsRx.Plugins.Persistence.Transformers 8 | { 9 | public class FromEntityDatabaseDataTransformer : IFromEntityDatabaseDataTransformer 10 | { 11 | public IFromEntityCollectionDataTransformer EntityCollectionDataTransformer { get; } 12 | public IEntityCollectionFactory EntityCollectionFactory { get; } 13 | 14 | public FromEntityDatabaseDataTransformer(IFromEntityCollectionDataTransformer entityCollectionDataTransformer, IEntityCollectionFactory entityCollectionFactory) 15 | { 16 | EntityCollectionDataTransformer = entityCollectionDataTransformer; 17 | EntityCollectionFactory = entityCollectionFactory; 18 | } 19 | 20 | public object Transform(object converted) 21 | { 22 | var entityDatabaseData = (EntityDatabaseData) converted; 23 | var entityDatabase = new EntityDatabase(EntityCollectionFactory); 24 | entityDatabaseData.EntityCollections 25 | .Select(EntityCollectionDataTransformer.Transform) 26 | .Cast() 27 | .ForEachRun(x => 28 | { 29 | if (entityDatabase.Collections.Any(e => e.Id == x.Id)) 30 | { 31 | entityDatabase.RemoveCollection(x.Id); 32 | 33 | } 34 | entityDatabase.AddCollection(x); 35 | }); 36 | 37 | return entityDatabase; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/IFromEntityCollectionDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using Persistity.Transformers; 2 | 3 | namespace EcsRx.Plugins.Persistence.Transformers 4 | { 5 | public interface IFromEntityCollectionDataTransformer : ITransformer 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/IFromEntityDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using Persistity.Transformers; 2 | 3 | namespace EcsRx.Plugins.Persistence.Transformers 4 | { 5 | public interface IFromEntityDataTransformer : ITransformer 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/IFromEntityDatabaseDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using Persistity.Transformers; 2 | 3 | namespace EcsRx.Plugins.Persistence.Transformers 4 | { 5 | public interface IFromEntityDatabaseDataTransformer : ITransformer 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/IToEntityCollectionDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using Persistity.Transformers; 2 | 3 | namespace EcsRx.Plugins.Persistence.Transformers 4 | { 5 | public interface IToEntityCollectionDataTransformer : ITransformer 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/IToEntityDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using Persistity.Transformers; 2 | 3 | namespace EcsRx.Plugins.Persistence.Transformers 4 | { 5 | public interface IToEntityDataTransformer : ITransformer 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/IToEntityDatabaseDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using Persistity.Transformers; 2 | 3 | namespace EcsRx.Plugins.Persistence.Transformers 4 | { 5 | public interface IToEntityDatabaseDataTransformer : ITransformer 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/ToEntityCollectionDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using EcsRx.Collections.Entity; 3 | using EcsRx.Plugins.Persistence.Data; 4 | 5 | namespace EcsRx.Plugins.Persistence.Transformers 6 | { 7 | public class ToEntityCollectionDataTransformer : IToEntityCollectionDataTransformer 8 | { 9 | public IToEntityDataTransformer EntityDataTransformer { get; } 10 | 11 | public ToEntityCollectionDataTransformer(IToEntityDataTransformer entityDataTransformer) 12 | { 13 | EntityDataTransformer = entityDataTransformer; 14 | } 15 | 16 | public object Transform(object original) 17 | { 18 | var collection = (IEntityCollection)original; 19 | 20 | var entityData = collection 21 | .Select(EntityDataTransformer.Transform) 22 | .Cast() 23 | .ToList(); 24 | 25 | return new EntityCollectionData 26 | { 27 | CollectionId = collection.Id, 28 | Entities = entityData 29 | }; 30 | } 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/ToEntityDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using EcsRx.Entities; 3 | using EcsRx.Plugins.Persistence.Data; 4 | 5 | namespace EcsRx.Plugins.Persistence.Transformers 6 | { 7 | public class ToEntityDataTransformer : IToEntityDataTransformer 8 | { 9 | public object Transform(object original) 10 | { 11 | var entity = (IEntity)original; 12 | return new EntityData 13 | { 14 | EntityId = entity.Id, 15 | Components = entity.Components.ToList() 16 | }; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Persistence/Transformers/ToEntityDatabaseDataTransformer.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using EcsRx.Collections.Database; 3 | using EcsRx.Collections.Entity; 4 | using EcsRx.Plugins.Persistence.Data; 5 | 6 | namespace EcsRx.Plugins.Persistence.Transformers 7 | { 8 | public class ToEntityDatabaseDataTransformer : IToEntityDatabaseDataTransformer 9 | { 10 | public IToEntityCollectionDataTransformer EntityCollectionDataTransformer { get; } 11 | 12 | public ToEntityDatabaseDataTransformer(IToEntityCollectionDataTransformer entityCollectionDataTransformer, IEntityCollectionFactory entityCollectionFactory) 13 | { 14 | EntityCollectionDataTransformer = entityCollectionDataTransformer; 15 | } 16 | 17 | public object Transform(object original) 18 | { 19 | var entityDatabase = (IEntityDatabase)original; 20 | 21 | var entityCollections = entityDatabase.Collections 22 | .Select(EntityCollectionDataTransformer.Transform) 23 | .Cast() 24 | .ToList(); 25 | 26 | return new EntityDatabaseData 27 | { 28 | EntityCollections = entityCollections 29 | }; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Transforms/Components/Transform2DComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | using SystemsRx.Plugins.Transforms.Models; 3 | 4 | namespace EcsRx.Plugins.Transforms.Components 5 | { 6 | public class Transform2DComponent : IComponent 7 | { 8 | /// 9 | /// The transform of the component 10 | /// 11 | public Transform2D Transform { get; set; } = new Transform2D(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Transforms/Components/TransformComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | using SystemsRx.Plugins.Transforms.Models; 3 | 4 | namespace EcsRx.Plugins.Transforms.Components 5 | { 6 | public class TransformComponent : IComponent 7 | { 8 | /// 9 | /// The transform of the component 10 | /// 11 | public Transform Transform { get; set; } = new Transform(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Transforms/EcsRx.Plugins.Transforms.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.1 6 | EcsRx.Plugins.Transforms 7 | Grofit (LP) 8 | https://github.com/ecsrx/ecsrx/blob/master/LICENSE 9 | https://github.com/ecsrx/ecsrx 10 | A plugin to provide a consistent way to represent 2d/3d transforms 11 | ecs rx reactive patterns ioc game-development xna monogame unity 12 | 8 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Transforms/TransformsPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SystemsRx.Infrastructure.Dependencies; 4 | using SystemsRx.Infrastructure.Plugins; 5 | using SystemsRx.Systems; 6 | 7 | namespace EcsRx.Plugins.Transforms 8 | { 9 | public class TransformsPlugin : ISystemsRxPlugin 10 | { 11 | public string Name => "EcsRx Transforms"; 12 | public Version Version { get; } = new Version("1.0.0"); 13 | 14 | public void SetupDependencies(IDependencyRegistry registry) 15 | { 16 | // Nothing needs registering 17 | } 18 | 19 | public IEnumerable GetSystemsForRegistration(IDependencyResolver resolver) => Array.Empty(); 20 | } 21 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/Components/ViewComponent.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Plugins.Views.Components 4 | { 5 | public class ViewComponent : IComponent 6 | { 7 | public bool DestroyWithView { get; set; } 8 | public object View { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/EcsRx.Plugins.Views.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 0.0.0 5 | netstandard2.1 6 | EcsRx.Plugins.Views 7 | Grofit (LP) 8 | https://github.com/ecsrx/ecsrx/blob/master/LICENSE 9 | https://github.com/ecsrx/ecsrx 10 | A set of view based conventions to assist with separating view from logic/data 11 | ecs rx reactive patterns ioc game-development view-separation xna monogame unity 12 | 8 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/Extensions/IEcsRxApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using SystemsRx.Extensions; 4 | using SystemsRx.Infrastructure.Extensions; 5 | using SystemsRx.Systems; 6 | using EcsRx.Infrastructure; 7 | using EcsRx.Plugins.Views.Systems; 8 | using EcsRx.Systems; 9 | 10 | namespace EcsRx.Plugins.Views.Extensions 11 | { 12 | public static class IEcsRxApplicationExtensions 13 | { 14 | /// 15 | /// Resolve all systems which have been bound in the order they need to be triggered 16 | /// 17 | /// The application to act on 18 | /// This ordering will be Setup, ViewResolvers, Anything Else 19 | public static IEnumerable GetAllBoundViewSystems(this IEcsRxApplication application) 20 | { 21 | var allSystems = application.DependencyResolver.ResolveAll(); 22 | 23 | return allSystems 24 | .OrderByDescending(x => x is ISetupSystem && !(x is IViewResolverSystem)) 25 | .ThenByDescending(x => x is IViewResolverSystem) 26 | .ThenByPriority(); 27 | } 28 | 29 | /// 30 | /// Resolve all systems which have been bound and register them in order with the systems executor 31 | /// 32 | /// The application to act on 33 | /// /// This ordering will be Setup, ViewResolvers, Anything Else 34 | public static void StartAllBoundViewSystems(this IEcsRxApplication application) 35 | { 36 | var orderedSystems = GetAllBoundViewSystems(application); 37 | orderedSystems.ForEachRun(application.SystemExecutor.AddSystem); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/Pooling/IViewPool.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Pools; 2 | 3 | namespace EcsRx.Plugins.Views.Pooling 4 | { 5 | public interface IViewPool : IPool 6 | { 7 | void PreAllocate(int allocationCount); 8 | void DeAllocate(int dellocationCount); 9 | void EmptyPool(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/Pooling/ViewObjectContainer.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Plugins.Views.Pooling 2 | { 3 | public class ViewObjectContainer 4 | { 5 | public object ViewObject { get; } 6 | public bool IsInUse { get; set; } 7 | 8 | public ViewObjectContainer(object viewObject) 9 | { 10 | ViewObject = viewObject; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/Systems/IViewResolverSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Systems; 2 | 3 | namespace EcsRx.Plugins.Views.Systems 4 | { 5 | public interface IViewResolverSystem : ISetupSystem, ITeardownSystem 6 | { 7 | 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/Systems/ViewResolverSystem.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Events; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Plugins.Views.Components; 6 | using EcsRx.Plugins.Views.ViewHandlers; 7 | 8 | namespace EcsRx.Plugins.Views.Systems 9 | { 10 | public abstract class ViewResolverSystem : IViewResolverSystem 11 | { 12 | public IEventSystem EventSystem { get; } 13 | 14 | public abstract IViewHandler ViewHandler { get; } 15 | 16 | public virtual IGroup Group => new Group(typeof(ViewComponent)); 17 | 18 | protected ViewResolverSystem(IEventSystem eventSystem) 19 | { 20 | EventSystem = eventSystem; 21 | } 22 | 23 | protected virtual void OnViewRemoved(IEntity entity, ViewComponent viewComponent) 24 | { ViewHandler.DestroyView(viewComponent.View); } 25 | 26 | protected abstract void OnViewCreated(IEntity entity, ViewComponent viewComponent); 27 | 28 | public virtual void Setup(IEntity entity) 29 | { 30 | var viewComponent = entity.GetComponent(); 31 | if (viewComponent.View != null) { return; } 32 | 33 | viewComponent.View = ViewHandler.CreateView(); 34 | OnViewCreated(entity, viewComponent); 35 | } 36 | 37 | public virtual void Teardown(IEntity entity) 38 | { 39 | var viewComponent = entity.GetComponent(); 40 | OnViewRemoved(entity, viewComponent); 41 | 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/ViewHandlers/IViewHandler.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Plugins.Views.ViewHandlers 2 | { 3 | public interface IViewHandler 4 | { 5 | void DestroyView(object view); 6 | void SetActiveState(object view, bool isActive); 7 | object CreateView(); 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Plugins.Views/ViewsPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SystemsRx.Infrastructure.Dependencies; 4 | using SystemsRx.Infrastructure.Plugins; 5 | using SystemsRx.Systems; 6 | 7 | namespace EcsRx.Plugins.Views 8 | { 9 | public class ViewsPlugin : ISystemsRxPlugin 10 | { 11 | public string Name => "Views Plugin"; 12 | public Version Version { get; } = new Version("1.0.0"); 13 | 14 | public void SetupDependencies(IDependencyRegistry registry) 15 | { 16 | // Nothing needs registering 17 | } 18 | 19 | public IEnumerable GetSystemsForRegistration(IDependencyResolver resolver) => Array.Empty(); 20 | } 21 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/EcsRx.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp3.1 4 | false 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {AD7EB200-BF3C-433B-96D2-D114DBE5B1E2} 20 | EcsRx.Infrastructure 21 | 22 | 23 | 24 | 25 | 26 | {5F5B6094-C56A-47E9-A835-127D0FFBF4C6} 27 | EcsRx 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/EcsRx.Tests/EcsRx/Components/Lookups/ComponentTypeLookupTests.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components.Lookups; 2 | using EcsRx.Tests.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | using Xunit; 6 | 7 | namespace EcsRx.Tests.EcsRx.Components.Lookups 8 | { 9 | public class ComponentTypeLookupTests 10 | { 11 | [Fact] 12 | public void requesting_non_existing_component_type_throws_keynotfound() 13 | { 14 | var sut = new ComponentTypeLookup(new Dictionary()); 15 | Assert.Throws(() => sut.GetComponentTypeId(typeof(TestComponentOne))); 16 | } 17 | 18 | [Fact] 19 | public void requesting_existing_component_type_returns_expected_component_id() 20 | { 21 | var sut = new ComponentTypeLookup(new Dictionary { {typeof(ComponentWithoutInterface), 1} }); 22 | Assert.Equal(1, sut.GetComponentTypeId(typeof(ComponentWithoutInterface))); 23 | } 24 | 25 | [Fact] 26 | public void requesting_non_existing_type_without_component_interface_throws_argumentexception() 27 | { 28 | var sut = new ComponentTypeLookup(new Dictionary()); 29 | Assert.Throws(() => sut.GetComponentTypeId(typeof(ComponentWithoutInterface))); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/EcsRx.Tests/EcsRx/Computeds/Models/TestComputedCollectionFromGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using EcsRx.Computeds.Collections; 5 | using EcsRx.Entities; 6 | using EcsRx.Extensions; 7 | using EcsRx.Groups.Observable; 8 | using EcsRx.Tests.Models; 9 | using SystemsRx.MicroRx.Subjects; 10 | 11 | namespace EcsRx.Tests.EcsRx.Computeds.Models 12 | { 13 | public class TestComputedCollectionFromGroup : ComputedCollectionFromGroup 14 | { 15 | public Subject ManuallyRefresh = new Subject(); 16 | 17 | public TestComputedCollectionFromGroup(IObservableGroup internalObservableGroup) : base(internalObservableGroup) 18 | { } 19 | 20 | public override IObservable RefreshWhen() 21 | { return ManuallyRefresh; } 22 | 23 | public override bool ShouldTransform(IEntity entity) 24 | { return entity.HasComponent(); } 25 | 26 | public override int Transform(IEntity entity) 27 | { return entity.GetHashCode(); } 28 | 29 | public override IEnumerable PostProcess(IEnumerable data) 30 | { return data.OrderBy(x => x); } 31 | } 32 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/EcsRx/Computeds/Models/TestComputedFromGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using EcsRx.Computeds; 4 | using EcsRx.Extensions; 5 | using EcsRx.Groups.Observable; 6 | using EcsRx.Tests.Models; 7 | using SystemsRx.MicroRx.Subjects; 8 | 9 | namespace EcsRx.Tests.EcsRx.Computeds.Models 10 | { 11 | public class TestComputedFromGroup : ComputedFromGroup 12 | { 13 | public Subject ManuallyRefresh = new Subject(); 14 | 15 | public TestComputedFromGroup(IObservableGroup internalObservableGroup) : base(internalObservableGroup) 16 | {} 17 | 18 | public override IObservable RefreshWhen() 19 | { return ManuallyRefresh; } 20 | 21 | public override double Transform(IObservableGroup observableGroup) 22 | { return observableGroup.Where(x => x.HasComponent()).Average(x => x.GetHashCode()); } 23 | } 24 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/EcsRx/Computeds/Models/TestComputedGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Computeds.Groups; 3 | using EcsRx.Entities; 4 | using EcsRx.Extensions; 5 | using EcsRx.Groups.Observable; 6 | using EcsRx.Tests.Models; 7 | using SystemsRx.MicroRx.Subjects; 8 | 9 | namespace EcsRx.Tests.EcsRx.Computeds.Models 10 | { 11 | public class TestComputedGroup : ComputedGroup 12 | { 13 | public Subject ManuallyRefresh = new Subject(); 14 | 15 | public TestComputedGroup(IObservableGroup internalObservableGroup) : base(internalObservableGroup) 16 | { } 17 | 18 | public override IObservable RefreshWhen() 19 | { return ManuallyRefresh; } 20 | 21 | public override bool IsEntityApplicable(IEntity entity) 22 | { return entity.HasComponent(); } 23 | } 24 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/EcsRx/ISystemExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using EcsRx.Extensions; 3 | using SystemsRx.Extensions; 4 | using EcsRx.Systems; 5 | using NSubstitute; 6 | using Xunit; 7 | 8 | namespace EcsRx.Tests.EcsRx 9 | { 10 | public class ISystemExtensionTests 11 | { 12 | public interface MultipleInterfaces : IReactToDataSystem, IReactToDataSystem{} 13 | 14 | [Fact] 15 | public void should_identify_if_system_is_reactive_data_system() 16 | { 17 | var fakeSystem = Substitute.For>(); 18 | Assert.True(fakeSystem.IsReactiveDataSystem()); 19 | } 20 | 21 | [Fact] 22 | public void should_get_interface_generic_type_from_reactive_data_system() 23 | { 24 | var fakeSystem = Substitute.For>(); 25 | var genericTypes = fakeSystem.GetGenericDataTypes(typeof(IReactToDataSystem<>)).ToArray(); 26 | 27 | Assert.Equal(1, genericTypes.Length); 28 | Assert.Contains(typeof(int), genericTypes); 29 | } 30 | 31 | [Fact] 32 | public void should_get_interface_generic_types_from_multiple_reactive_data_system() 33 | { 34 | var fakeSystem = Substitute.For(); 35 | var genericTypes = fakeSystem.GetGenericDataTypes(typeof(IReactToDataSystem<>)).ToArray(); 36 | 37 | Assert.Equal(2, genericTypes.Length); 38 | Assert.Contains(typeof(int), genericTypes); 39 | Assert.Contains(typeof(float), genericTypes); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/EcsRx/Observables/ObservableGroupTokenTests.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Groups.Observable; 2 | using Xunit; 3 | 4 | namespace EcsRx.Tests.EcsRx.Observables 5 | { 6 | public class ObservableGroupTokenTests 7 | { 8 | [Fact] 9 | public void should_correctly_differentiate_tokens() 10 | { 11 | var defaultRequired = new[] {1}; 12 | var defaultExcluded = new int[0]; 13 | var token1 = new ObservableGroupToken(defaultRequired, defaultExcluded); 14 | var token2 = new ObservableGroupToken(defaultRequired, defaultExcluded, 1); 15 | var token3 = new ObservableGroupToken(defaultRequired, defaultExcluded, 1, 2); 16 | 17 | Assert.NotEqual(token1, token2); 18 | Assert.NotEqual(token1, token3); 19 | Assert.NotEqual(token2, token3); 20 | 21 | Assert.NotEqual(token1.GetHashCode(), token2.GetHashCode()); 22 | Assert.NotEqual(token1.GetHashCode(), token3.GetHashCode()); 23 | Assert.NotEqual(token2.GetHashCode(), token3.GetHashCode()); 24 | 25 | Assert.Equal(token1, token1); 26 | Assert.Equal(token2, token2); 27 | Assert.Equal(token3, token3); 28 | 29 | Assert.Equal(token1.GetHashCode(), token1.GetHashCode()); 30 | Assert.Equal(token2.GetHashCode(), token2.GetHashCode()); 31 | Assert.Equal(token3.GetHashCode(), token3.GetHashCode()); 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Helpers/ManualUpdateScheduler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Subjects; 3 | using SystemsRx.Scheduling; 4 | 5 | namespace EcsRx.Tests.Helpers 6 | { 7 | public class ManualUpdateScheduler : IUpdateScheduler 8 | { 9 | public ElapsedTime ElapsedTime { get; set; } 10 | 11 | public Subject ElapsedTimeTrigger { get; } 12 | 13 | public ManualUpdateScheduler(Subject elapsedTimeTrigger) 14 | { ElapsedTimeTrigger = elapsedTimeTrigger; } 15 | 16 | public void Dispose() 17 | { ElapsedTimeTrigger.Dispose(); } 18 | 19 | public IObservable OnPreUpdate => ElapsedTimeTrigger; 20 | public IObservable OnUpdate => ElapsedTimeTrigger; 21 | public IObservable OnPostUpdate => ElapsedTimeTrigger; 22 | } 23 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/ComplexObject.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Tests.Models 2 | { 3 | public class ComplexObject 4 | { 5 | public int Value { get; } 6 | public string Name { get; } 7 | 8 | public ComplexObject(int value, string name) 9 | { 10 | Value = value; 11 | Name = name; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/ComponentWithReactiveProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Components; 3 | using SystemsRx.ReactiveData; 4 | 5 | namespace EcsRx.Tests.Models 6 | { 7 | public class ComponentWithReactiveProperty : IComponent, IDisposable 8 | { 9 | public ReactiveProperty SomeNumber { get; } = new ReactiveProperty(); 10 | 11 | public void Dispose() 12 | { SomeNumber?.Dispose(); } 13 | } 14 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/ComponentWithoutInterface.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Tests.Models 2 | { 3 | public class ComponentWithoutInterface 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/TestComponentOne.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Tests.Models 4 | { 5 | public class TestComponentOne : IComponent 6 | { 7 | public string Data { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/TestComponentThree.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Tests.Models 4 | { 5 | public class TestComponentThree : IComponent 6 | { 7 | public string Data { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/TestComponentTwo.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Tests.Models 4 | { 5 | public class TestComponentTwo : IComponent 6 | { 7 | public string Data { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/TestDisposableComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Components; 3 | 4 | namespace EcsRx.Tests.Models 5 | { 6 | public class TestDisposableComponent : IComponent, IDisposable 7 | { 8 | public bool isDisposed = false; 9 | 10 | public void Dispose() 11 | { isDisposed = true; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/TestStructComponentOne.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Tests.Models 4 | { 5 | public struct TestStructComponentOne : IComponent 6 | { 7 | public int Data; 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Models/TestStructComponentTwo.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | 3 | namespace EcsRx.Tests.Models 4 | { 5 | public struct TestStructComponentTwo : IComponent 6 | { 7 | public float Data; 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Plugins/GroupBinding/Handlers/Helpers/SystemMissingGroup.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Systems; 2 | using EcsRx.Groups.Observable; 3 | using EcsRx.Plugins.GroupBinding.Attributes; 4 | 5 | namespace EcsRx.Tests.Plugins.GroupBinding.Handlers.Helpers 6 | { 7 | public class SystemMissingGroup : ISystem 8 | { 9 | [FromGroup()] 10 | public IObservableGroup ObservableGroupA { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Plugins/GroupBinding/Handlers/Helpers/SystemWithAutoGroupPopulation.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Systems; 2 | using EcsRx.Groups; 3 | using EcsRx.Groups.Observable; 4 | using EcsRx.Plugins.GroupBinding.Attributes; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | using EcsRx.Attributes; 8 | 9 | namespace EcsRx.Tests.Plugins.GroupBinding.Handlers.Helpers 10 | { 11 | [CollectionAffinity(3)] 12 | public class SystemWithAutoGroupPopulation : ISystem, IGroupSystem 13 | { 14 | public IGroup Group => new TestGroupA(); 15 | 16 | [FromGroup(typeof(TestGroupA))] 17 | public IObservableGroup ObservableGroupA { get; set; } 18 | 19 | [FromGroup(typeof(TestGroupA))] 20 | public IObservableGroup IgnoredObservableGroup { get; } 21 | 22 | [FromComponents(typeof(TestComponentTwo))] 23 | public IObservableGroup ObservableGroupB { get; set; } 24 | 25 | public int IgnoredProperty { get; set; } 26 | 27 | [FromGroup] 28 | public IObservableGroup ObservableGroupC; 29 | 30 | [FromGroup(typeof(TestGroupA))] 31 | [CollectionAffinity(2)] 32 | public IObservableGroup ObservableGroupAInCollection2; 33 | 34 | 35 | [FromComponents(typeof(TestComponentTwo))] 36 | [CollectionAffinity(5)] 37 | public IObservableGroup ObservableGroupBInCollection5; 38 | 39 | [FromGroup] 40 | [CollectionAffinity(7)] 41 | public IObservableGroup ObservableGroupCInCollection7 { get; set; } 42 | 43 | public int IgnoredField; 44 | } 45 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Plugins/GroupBinding/Handlers/Helpers/TestGroupA.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Groups; 3 | using EcsRx.Tests.Models; 4 | 5 | namespace EcsRx.Tests.Plugins.GroupBinding.Handlers.Helpers 6 | { 7 | public class TestGroupA : IGroup 8 | { 9 | public Type[] RequiredComponents { get; set; } = {typeof(TestComponentOne)}; 10 | public Type[] ExcludedComponents { get; set; } = Array.Empty(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingBasicEntitySystem1.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Collections.Entity; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | using SystemsRx.Scheduling; 8 | 9 | namespace EcsRx.Tests.Systems.DeletingScenarios 10 | { 11 | public class DeletingBasicEntitySystem1 : IBasicEntitySystem 12 | { 13 | public IGroup Group => new Group().WithComponent(); 14 | 15 | public IEntityCollection EntityCollection { get; } 16 | 17 | public DeletingBasicEntitySystem1(IEntityCollection entityCollection) 18 | { EntityCollection = entityCollection; } 19 | 20 | public void Process(IEntity entity, ElapsedTime elapsedTime) 21 | { EntityCollection.RemoveEntity(entity.Id); } 22 | } 23 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingBasicEntitySystem2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | using SystemsRx.Scheduling; 8 | 9 | namespace EcsRx.Tests.Systems.DeletingScenarios 10 | { 11 | public class DeletingBasicEntitySystem2 : IBasicEntitySystem 12 | { 13 | public IGroup Group => new Group().WithComponent(); 14 | 15 | public void Process(IEntity entity, ElapsedTime elapsedTime) 16 | { throw new Exception("Should Not Be Called"); } 17 | } 18 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingOverlappingBasicEntitySystem1.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Collections.Entity; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | using SystemsRx.Scheduling; 8 | 9 | namespace EcsRx.Tests.Systems.DeletingScenarios 10 | { 11 | public class DeletingOverlappingBasicEntitySystem1 : IBasicEntitySystem 12 | { 13 | public IGroup Group => new Group() 14 | .WithComponent() 15 | .WithComponent(); 16 | 17 | public IEntityCollection EntityCollection { get; } 18 | 19 | public DeletingOverlappingBasicEntitySystem1(IEntityCollection entityCollection) 20 | { EntityCollection = entityCollection; } 21 | 22 | public void Process(IEntity entity, ElapsedTime elapsedTime) 23 | { EntityCollection.RemoveEntity(entity.Id); } 24 | } 25 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingOverlappingBasicEntitySystem2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | using SystemsRx.Scheduling; 8 | 9 | namespace EcsRx.Tests.Systems.DeletingScenarios 10 | { 11 | public class DeletingOverlappingBasicEntitySystem2 : IBasicEntitySystem 12 | { 13 | public IGroup Group => new Group() 14 | .WithComponent() 15 | .WithComponent(); 16 | 17 | public void Process(IEntity entity, ElapsedTime elapsedTime) 18 | { throw new Exception("Should Not Be Called"); } 19 | } 20 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingOverlappingReactiveEntityTestSystem1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Collections.Entity; 4 | using EcsRx.Entities; 5 | using EcsRx.Extensions; 6 | using EcsRx.Groups; 7 | using EcsRx.Systems; 8 | using EcsRx.Tests.Models; 9 | 10 | namespace EcsRx.Tests.Systems.DeletingScenarios 11 | { 12 | public class DeletingOverlappingReactiveEntityTestSystem1 : IReactToEntitySystem 13 | { 14 | public IGroup Group => new Group() 15 | .WithComponent() 16 | .WithComponent(); 17 | 18 | public IEntityCollection EntityCollection { get; } 19 | 20 | public DeletingOverlappingReactiveEntityTestSystem1(IEntityCollection entityCollection) 21 | { EntityCollection = entityCollection; } 22 | 23 | public IObservable ReactToEntity(IEntity entity) 24 | { return entity.GetComponent().SomeNumber.Select(x => entity); } 25 | 26 | public void Process(IEntity entity) 27 | { EntityCollection.RemoveEntity(entity.Id); } 28 | } 29 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingOverlappingReactiveEntityTestSystem2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Entities; 4 | using EcsRx.Extensions; 5 | using EcsRx.Groups; 6 | using EcsRx.Systems; 7 | using EcsRx.Tests.Models; 8 | 9 | namespace EcsRx.Tests.Systems.DeletingScenarios 10 | { 11 | public class DeletingOverlappingReactiveEntityTestSystem2 : IReactToEntitySystem 12 | { 13 | public IGroup Group => new Group() 14 | .WithComponent() 15 | .WithComponent(); 16 | 17 | public IObservable ReactToEntity(IEntity entity) 18 | { return entity.GetComponent().SomeNumber.Select(x => entity); } 19 | 20 | public void Process(IEntity entity) 21 | { throw new Exception("Should Not Get Called"); } 22 | } 23 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingOverlappingSetupTestSystem1.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Collections.Entity; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | 8 | namespace EcsRx.Tests.Systems.DeletingScenarios 9 | { 10 | public class DeletingOverlappingSetupTestSystem1 : ISetupSystem 11 | { 12 | public IGroup Group => new Group() 13 | .WithComponent() 14 | .WithComponent(); 15 | 16 | public IEntityCollection EntityCollection { get; } 17 | 18 | public DeletingOverlappingSetupTestSystem1(IEntityCollection entityCollection) 19 | { EntityCollection = entityCollection; } 20 | 21 | public void Setup(IEntity entity) 22 | { EntityCollection.RemoveEntity(entity.Id); } 23 | } 24 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingOverlappingSetupTestSystem2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | 8 | namespace EcsRx.Tests.Systems.DeletingScenarios 9 | { 10 | public class DeletingOverlappingSetupTestSystem2 : ISetupSystem 11 | { 12 | public IGroup Group => new Group() 13 | .WithComponent() 14 | .WithComponent(); 15 | 16 | public void Setup(IEntity entity) 17 | { throw new Exception("Should Not Get Called"); } 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingReactiveDataTestSystem1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Collections.Entity; 3 | using EcsRx.Entities; 4 | using EcsRx.Extensions; 5 | using EcsRx.Groups; 6 | using EcsRx.Systems; 7 | using EcsRx.Tests.Models; 8 | 9 | namespace EcsRx.Tests.Systems.DeletingScenarios 10 | { 11 | public class DeletingReactiveDataTestSystem1 : IReactToDataSystem 12 | { 13 | public IGroup Group => new Group().WithComponent(); 14 | public IEntityCollection EntityCollection { get; } 15 | 16 | public DeletingReactiveDataTestSystem1(IEntityCollection entityCollection) 17 | { EntityCollection = entityCollection; } 18 | 19 | public IObservable ReactToData(IEntity entity) 20 | { return entity.GetComponent().SomeNumber; } 21 | 22 | public void Process(IEntity entity, int reactionData) 23 | { EntityCollection.RemoveEntity(entity.Id); } 24 | } 25 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingReactiveDataTestSystem2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | 8 | namespace EcsRx.Tests.Systems.DeletingScenarios 9 | { 10 | public class DeletingReactiveDataTestSystem2 : IReactToDataSystem 11 | { 12 | public IGroup Group => new Group().WithComponent(); 13 | 14 | public IObservable ReactToData(IEntity entity) 15 | { return entity.GetComponent().SomeNumber; } 16 | 17 | public void Process(IEntity entity, int reactionData) 18 | { throw new Exception("Should Not Get Called"); } 19 | } 20 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingReactiveEntityTestSystem1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Collections.Entity; 4 | using EcsRx.Entities; 5 | using EcsRx.Extensions; 6 | using EcsRx.Groups; 7 | using EcsRx.Systems; 8 | using EcsRx.Tests.Models; 9 | 10 | namespace EcsRx.Tests.Systems.DeletingScenarios 11 | { 12 | public class DeletingReactiveEntityTestSystem1 : IReactToEntitySystem 13 | { 14 | public IGroup Group => new Group().WithComponent(); 15 | public IEntityCollection EntityCollection { get; } 16 | 17 | public DeletingReactiveEntityTestSystem1(IEntityCollection entityCollection) 18 | { EntityCollection = entityCollection; } 19 | 20 | public IObservable ReactToEntity(IEntity entity) 21 | { return entity.GetComponent().SomeNumber.Select(x => entity); } 22 | 23 | public void Process(IEntity entity) 24 | { EntityCollection.RemoveEntity(entity.Id); } 25 | } 26 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingReactiveEntityTestSystem2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Entities; 4 | using EcsRx.Extensions; 5 | using EcsRx.Groups; 6 | using EcsRx.Systems; 7 | using EcsRx.Tests.Models; 8 | 9 | namespace EcsRx.Tests.Systems.DeletingScenarios 10 | { 11 | public class DeletingReactiveEntityTestSystem2 : IReactToEntitySystem 12 | { 13 | public IGroup Group => new Group().WithComponent(); 14 | 15 | public IObservable ReactToEntity(IEntity entity) 16 | { return entity.GetComponent().SomeNumber.Select(x => entity); } 17 | 18 | public void Process(IEntity entity) 19 | { throw new Exception("Should Not Get Called"); } 20 | } 21 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingSetupTestSystem1.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Collections.Entity; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | 8 | namespace EcsRx.Tests.Systems.DeletingScenarios 9 | { 10 | public class DeletingSetupTestSystem1 : ISetupSystem 11 | { 12 | public IGroup Group => new Group().WithComponent(); 13 | 14 | public IEntityCollection EntityCollection { get; } 15 | 16 | public DeletingSetupTestSystem1(IEntityCollection entityCollection) 17 | { EntityCollection = entityCollection; } 18 | 19 | public void Setup(IEntity entity) 20 | { EntityCollection.RemoveEntity(entity.Id); } 21 | } 22 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/DeletingScenarios/DeletingSetupTestSystem2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Extensions; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using EcsRx.Tests.Models; 7 | 8 | namespace EcsRx.Tests.Systems.DeletingScenarios 9 | { 10 | public class DeletingSetupTestSystem2 : ISetupSystem 11 | { 12 | public IGroup Group => new Group().WithComponent(); 13 | 14 | public void Setup(IEntity entity) 15 | { throw new Exception("Should Not Get Called"); } 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/Handlers/DefaultPriorityHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Executor.Handlers; 3 | using SystemsRx.Systems; 4 | 5 | namespace EcsRx.Tests.Systems.Handlers 6 | { 7 | public class DefaultPriorityHandler : IConventionalSystemHandler 8 | { 9 | private Action _doSomethingOnSetup; 10 | private Action _doSomethingOnDestroy; 11 | 12 | public DefaultPriorityHandler(Action doSomethingOnSetup = null, Action doSomethingOnDestroy = null) 13 | { 14 | _doSomethingOnSetup = doSomethingOnSetup; 15 | _doSomethingOnDestroy = doSomethingOnDestroy; 16 | } 17 | 18 | public void Dispose() {} 19 | public bool CanHandleSystem(ISystem system) => true; 20 | 21 | public void SetupSystem(ISystem system) 22 | { _doSomethingOnSetup?.Invoke(); } 23 | 24 | public void DestroySystem(ISystem system) 25 | { _doSomethingOnDestroy?.Invoke(); } 26 | } 27 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/Handlers/HighPriorityHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Attributes; 3 | using SystemsRx.Executor.Handlers; 4 | using SystemsRx.Systems; 5 | using SystemsRx.Types; 6 | 7 | namespace EcsRx.Tests.Systems.Handlers 8 | { 9 | [Priority(PriorityTypes.High)] 10 | public class HighPriorityHandler : IConventionalSystemHandler 11 | { 12 | private Action _doSomethingOnSetup; 13 | private Action _doSomethingOnDestroy; 14 | 15 | public HighPriorityHandler(Action doSomethingOnSetup = null, Action doSomethingOnDestroy = null) 16 | { 17 | _doSomethingOnSetup = doSomethingOnSetup; 18 | _doSomethingOnDestroy = doSomethingOnDestroy; 19 | } 20 | 21 | public void Dispose() {} 22 | public bool CanHandleSystem(ISystem system) => true; 23 | 24 | public void SetupSystem(ISystem system) 25 | { _doSomethingOnSetup?.Invoke(); } 26 | 27 | public void DestroySystem(ISystem system) 28 | { _doSomethingOnDestroy?.Invoke(); } 29 | } 30 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/Handlers/HigherPriorityHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Attributes; 3 | using SystemsRx.Executor.Handlers; 4 | using SystemsRx.Systems; 5 | using SystemsRx.Types; 6 | 7 | namespace EcsRx.Tests.Systems.Handlers 8 | { 9 | [Priority(PriorityTypes.Higher)] 10 | public class HigherPriorityHandler : IConventionalSystemHandler 11 | { 12 | private Action _doSomethingOnSetup; 13 | private Action _doSomethingOnDestroy; 14 | 15 | public HigherPriorityHandler(Action doSomethingOnSetup = null, Action doSomethingOnDestroy = null) 16 | { 17 | _doSomethingOnSetup = doSomethingOnSetup; 18 | _doSomethingOnDestroy = doSomethingOnDestroy; 19 | } 20 | 21 | public void Dispose() {} 22 | public bool CanHandleSystem(ISystem system) => true; 23 | 24 | public void SetupSystem(ISystem system) 25 | { _doSomethingOnSetup?.Invoke(); } 26 | 27 | public void DestroySystem(ISystem system) 28 | { _doSomethingOnDestroy?.Invoke(); } 29 | } 30 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/Handlers/LowerPriorityHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Attributes; 3 | using SystemsRx.Executor.Handlers; 4 | using SystemsRx.Systems; 5 | using SystemsRx.Types; 6 | 7 | namespace EcsRx.Tests.Systems.Handlers 8 | { 9 | [Priority(PriorityTypes.Low)] 10 | public class LowerPriorityHandler : IConventionalSystemHandler 11 | { 12 | private Action _doSomethingOnSetup; 13 | private Action _doSomethingOnDestroy; 14 | 15 | public LowerPriorityHandler(Action doSomethingOnSetup = null, Action doSomethingOnDestroy = null) 16 | { 17 | _doSomethingOnSetup = doSomethingOnSetup; 18 | _doSomethingOnDestroy = doSomethingOnDestroy; 19 | } 20 | 21 | public void Dispose() {} 22 | public bool CanHandleSystem(ISystem system) => true; 23 | 24 | public void SetupSystem(ISystem system) 25 | { _doSomethingOnSetup?.Invoke(); } 26 | 27 | public void DestroySystem(ISystem system) 28 | { _doSomethingOnDestroy?.Invoke(); } 29 | } 30 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/PriorityScenarios/DefaultPriorityGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using EcsRx.Groups; 3 | using EcsRx.Plugins.Views.Systems; 4 | using EcsRx.Systems; 5 | 6 | namespace EcsRx.Tests.Systems.PriorityScenarios 7 | { 8 | public class DefaultPriorityGroupSystem : IGroupSystem 9 | { 10 | public IGroup Group => null; 11 | } 12 | 13 | public class DefaultPrioritySetupSystem : ISetupSystem 14 | { 15 | public IGroup Group => null; 16 | public void Setup(IEntity entity){} 17 | } 18 | 19 | public class DefaultPriorityViewResolverSystem : IViewResolverSystem 20 | { 21 | public IGroup Group => null; 22 | public void Teardown(IEntity entity){} 23 | public void Setup(IEntity entity){} 24 | } 25 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/PriorityScenarios/HigherThanDefaultPriorityGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Groups; 2 | using EcsRx.Systems; 3 | using SystemsRx.Attributes; 4 | 5 | namespace EcsRx.Tests.Systems.PriorityScenarios 6 | { 7 | [Priority(1)] 8 | public class HigherThanDefaultPriorityGroupSystem : IGroupSystem 9 | { 10 | public IGroup Group => null; 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/PriorityScenarios/HighestPriorityGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using EcsRx.Groups; 3 | using EcsRx.Plugins.Views.Systems; 4 | using EcsRx.Systems; 5 | using SystemsRx.Attributes; 6 | 7 | namespace EcsRx.Tests.Systems.PriorityScenarios 8 | { 9 | [Priority(100)] 10 | public class HighestPriorityGroupSystem : IGroupSystem 11 | { 12 | public IGroup Group => null; 13 | } 14 | 15 | [Priority(101)] 16 | public class HighestPrioritySetupSystem : ISetupSystem 17 | { 18 | public IGroup Group => null; 19 | 20 | public void Setup(IEntity entity) {} 21 | } 22 | 23 | [Priority(102)] 24 | public class HighestPriorityViewResolverSystem : IViewResolverSystem 25 | { 26 | public IGroup Group => null; 27 | public void Teardown(IEntity entity){} 28 | public void Setup(IEntity entity){} 29 | } 30 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/PriorityScenarios/LowerThanDefaultPriorityGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Groups; 2 | using EcsRx.Systems; 3 | using SystemsRx.Attributes; 4 | 5 | namespace EcsRx.Tests.Systems.PriorityScenarios 6 | { 7 | [Priority(-1)] 8 | public class LowerThanDefaultPriorityGroupSystem : IGroupSystem 9 | { 10 | public IGroup Group => null; 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/PriorityScenarios/LowestPriorityGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using EcsRx.Groups; 3 | using EcsRx.Plugins.Views.Systems; 4 | using EcsRx.Systems; 5 | using SystemsRx.Attributes; 6 | 7 | namespace EcsRx.Tests.Systems.PriorityScenarios 8 | { 9 | [Priority(-100)] 10 | public class LowestPriorityGroupSystem : IGroupSystem 11 | { 12 | public IGroup Group => null; 13 | } 14 | 15 | [Priority(-101)] 16 | public class LowestPrioritySetupSystem : ISetupSystem 17 | { 18 | public IGroup Group => null; 19 | 20 | public void Setup(IEntity entity) {} 21 | } 22 | 23 | [Priority(-102)] 24 | public class LowestPriorityViewResolverSystem : IViewResolverSystem 25 | { 26 | public IGroup Group => null; 27 | public void Teardown(IEntity entity){} 28 | public void Setup(IEntity entity){} 29 | } 30 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/ReactiveDataTestSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using EcsRx.Entities; 4 | using EcsRx.Extensions; 5 | using EcsRx.Groups; 6 | using EcsRx.Systems; 7 | using EcsRx.Tests.Models; 8 | 9 | namespace EcsRx.Tests.Systems 10 | { 11 | public class ReactiveDataTestSystem : IReactToDataSystem 12 | { 13 | public IGroup Group => new Group().WithComponent(); 14 | 15 | public IObservable ReactToData(IEntity entity) 16 | { 17 | return Observable.Timer(TimeSpan.FromSeconds(1)).Select(x => 0.1f); 18 | } 19 | 20 | public void Process(IEntity entity, float reactionData) 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/TestSetupSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using EcsRx.Extensions; 3 | using EcsRx.Groups; 4 | using EcsRx.Systems; 5 | using EcsRx.Tests.Models; 6 | 7 | namespace EcsRx.Tests.Systems 8 | { 9 | public class TestSetupSystem : ISetupSystem 10 | { 11 | public IGroup Group => new Group(typeof(TestComponentOne)); 12 | 13 | public void Setup(IEntity entity) 14 | { 15 | var testComponent = entity.GetComponent(); 16 | testComponent.Data = "woop"; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx.Tests/Systems/TestViewResolverSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Events; 3 | using EcsRx.Entities; 4 | using EcsRx.Groups; 5 | using EcsRx.Plugins.Views.Components; 6 | using EcsRx.Plugins.Views.Systems; 7 | using EcsRx.Plugins.Views.ViewHandlers; 8 | 9 | namespace EcsRx.Tests.Systems 10 | { 11 | public class TestViewResolverSystem : ViewResolverSystem 12 | { 13 | public override IViewHandler ViewHandler { get; } 14 | public override IGroup Group { get; } 15 | 16 | public Action OnSetup { get; set; } 17 | public Action OnTeardown { get; set; } 18 | 19 | public TestViewResolverSystem(IEventSystem eventSystem, IGroup group) : base(eventSystem) 20 | { 21 | Group = group; 22 | } 23 | 24 | protected override void OnViewCreated(IEntity entity, ViewComponent viewComponent) 25 | { 26 | 27 | } 28 | 29 | public override void Setup(IEntity entity) 30 | { 31 | OnSetup?.Invoke(entity); 32 | } 33 | 34 | public override void Teardown(IEntity entity) 35 | { 36 | OnTeardown?.Invoke(entity); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/EcsRx/Attributes/CollectionAffinityAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Collections.Database; 3 | 4 | namespace EcsRx.Attributes 5 | { 6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field)] 7 | public class CollectionAffinityAttribute : Attribute 8 | { 9 | public int[] CollectionIds { get; } 10 | 11 | public CollectionAffinityAttribute(int collectionId = EntityCollectionLookups.DefaultCollectionId) 12 | { CollectionIds = new []{collectionId}; } 13 | 14 | public CollectionAffinityAttribute(params int[] collectionIds) 15 | { CollectionIds = collectionIds; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx/Blueprints/IBlueprint.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | 3 | namespace EcsRx.Blueprints 4 | { 5 | /// 6 | /// Blueprints are a pre-defined setup routine for an entity, this is meant to setup required 7 | /// components and default values. Such as if you wanted to setup an NPC who needed both Moveable, Talkable 8 | /// components and default values around movement speed etc. 9 | /// 10 | /// 11 | /// You *can* apply multiple blueprints after an entity has been created, but this is meant for you to be able to 12 | /// have a mixin style approach to setting up entity config data, it is not meant to replace an 13 | /// ISetupSystem which will do more than just setup entity config but also run logic on the component 14 | /// 15 | public interface IBlueprint 16 | { 17 | /// 18 | /// Applies the given blueprint to the entity 19 | /// 20 | /// The entity to be configured 21 | void Apply(IEntity entity); 22 | } 23 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Database/EntityCollectionLookups.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Collections.Database 2 | { 3 | public static class EntityCollectionLookups 4 | { 5 | public const int NoCollectionDefined = -1; 6 | public const int DefaultCollectionId = 0; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/EcsRx/Collections/Entity/DefaultEntityCollectionFactory.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | 3 | namespace EcsRx.Collections.Entity 4 | { 5 | public class DefaultEntityCollectionFactory : IEntityCollectionFactory 6 | { 7 | private readonly IEntityFactory _entityFactory; 8 | 9 | public DefaultEntityCollectionFactory(IEntityFactory entityFactory) 10 | { 11 | _entityFactory = entityFactory; 12 | } 13 | 14 | public IEntityCollection Create(int id) 15 | { 16 | return new EntityCollection(id, _entityFactory); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Entity/IEntityCollectionFactory.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Factories; 2 | 3 | namespace EcsRx.Collections.Entity 4 | { 5 | /// 6 | /// Creates an entity collection for a given name 7 | /// 8 | /// 9 | /// This is meant to be replaceable so you can create your own implementation and replace for using 10 | /// your own entity collection implementations 11 | /// 12 | public interface IEntityCollectionFactory : IFactory 13 | { 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Entity/IEntityCollectionQuery.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Collections.Entity 5 | { 6 | /// 7 | /// A pre made query which will extract relevant entities from the entity collection, this is useful 8 | /// for wrapping up complex logic. i.e Get all entities who have a component with Health > 25% 9 | /// 10 | /// 11 | /// This will run on the live data so every query execution will cause an enumeration through 12 | /// the collection, this is often undesired for performance reasons but is useful for one off 13 | /// style queries. 14 | /// 15 | public interface IEntityCollectionQuery 16 | { 17 | /// 18 | /// Acts as a way to filter the entity data. 19 | /// 20 | /// 21 | /// This is often called automatically by other methods which act on the collection itself so its 22 | /// rare that you would ever need to Execute yourself manually. 23 | /// 24 | /// The list of entities to enumerate 25 | /// A filtered collection of entities to enumerate through 26 | IEnumerable Execute(IEnumerable entityList); 27 | } 28 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Entity/INotifyingCollection.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Collections.Entity 2 | { 3 | public interface INotifyingCollection : INotifyingEntityCollection, INotifyingEntityComponentChanges 4 | { } 5 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Entity/INotifyingEntityCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Collections.Events; 3 | 4 | namespace EcsRx.Collections.Entity 5 | { 6 | public interface INotifyingEntityCollection 7 | { 8 | IObservable EntityAdded { get; } 9 | IObservable EntityRemoved { get; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Entity/INotifyingEntityComponentChanges.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Collections.Events; 3 | 4 | namespace EcsRx.Collections.Entity 5 | { 6 | public interface INotifyingEntityComponentChanges 7 | { 8 | IObservable EntityComponentsAdded { get; } 9 | IObservable EntityComponentsRemoving { get; } 10 | IObservable EntityComponentsRemoved { get; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Events/CollectionElementChangedEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace EcsRx.Collections.Events 5 | { 6 | public readonly struct CollectionElementChangedEvent : IEquatable> 7 | { 8 | public readonly int Index; 9 | public readonly T OldValue; 10 | public readonly T NewValue; 11 | 12 | public CollectionElementChangedEvent(int index, T oldValue, T newValue) 13 | { 14 | Index = index; 15 | OldValue = oldValue; 16 | NewValue = newValue; 17 | } 18 | 19 | public bool Equals(CollectionElementChangedEvent other) 20 | { 21 | return Index == other.Index && EqualityComparer.Default.Equals(OldValue, other.OldValue) && EqualityComparer.Default.Equals(NewValue, other.NewValue); 22 | } 23 | 24 | public override bool Equals(object obj) 25 | { 26 | if (ReferenceEquals(null, obj)) {return false;} 27 | return obj is CollectionElementChangedEvent other && Equals(other); 28 | } 29 | 30 | public override int GetHashCode() 31 | { 32 | unchecked 33 | { 34 | var hashCode = Index; 35 | hashCode = (hashCode * 397) ^ EqualityComparer.Default.GetHashCode(OldValue); 36 | hashCode = (hashCode * 397) ^ EqualityComparer.Default.GetHashCode(NewValue); 37 | return hashCode; 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Events/CollectionEntityEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Collections.Events 5 | { 6 | public readonly struct CollectionEntityEvent : IEquatable 7 | { 8 | public readonly IEntity Entity; 9 | 10 | public CollectionEntityEvent(IEntity entity) 11 | { 12 | Entity = entity; 13 | } 14 | 15 | public bool Equals(CollectionEntityEvent other) 16 | { 17 | return Equals(Entity, other.Entity); 18 | } 19 | 20 | public override bool Equals(object obj) 21 | { 22 | if (ReferenceEquals(null, obj)) {return false;} 23 | return obj is CollectionEntityEvent other && Equals(other); 24 | } 25 | 26 | public override int GetHashCode() 27 | { 28 | return (Entity != null ? Entity.GetHashCode() : 0); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/Events/ComponentsChangedEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Collections.Events 5 | { 6 | public readonly struct ComponentsChangedEvent : IEquatable 7 | { 8 | public readonly IEntity Entity; 9 | public readonly int[] ComponentTypeIds; 10 | 11 | public ComponentsChangedEvent(IEntity entity, int[] componentTypeIds) 12 | { 13 | Entity = entity; 14 | ComponentTypeIds = componentTypeIds; 15 | } 16 | 17 | public bool Equals(ComponentsChangedEvent other) 18 | { 19 | return Equals(Entity, other.Entity) && Equals(ComponentTypeIds, other.ComponentTypeIds); 20 | } 21 | 22 | public override bool Equals(object obj) 23 | { 24 | if (ReferenceEquals(null, obj)) {return false;} 25 | return obj is ComponentsChangedEvent other && Equals(other); 26 | } 27 | 28 | public override int GetHashCode() 29 | { 30 | unchecked 31 | { 32 | return ((Entity != null ? Entity.GetHashCode() : 0) * 397) ^ (ComponentTypeIds != null ? ComponentTypeIds.GetHashCode() : 0); 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/EcsRx/Collections/IObservableGroupManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EcsRx.Groups; 4 | using EcsRx.Groups.Observable; 5 | 6 | namespace EcsRx.Collections 7 | { 8 | public interface IObservableGroupManager : IDisposable 9 | { 10 | IReadOnlyList ObservableGroups { get; } 11 | IEnumerable GetApplicableGroups(int[] componentTypeIds); 12 | 13 | /// 14 | /// Gets an ObservableGroup which will observe the given group and maintain a collection of 15 | /// entities which are applicable. This is the preferred way to access entities inside collections. 16 | /// 17 | /// 18 | /// It is worth noting that IObservableGroup instances are cached within the manager, so if there is 19 | /// a request for an observable group targetting the same underlying components (not the IGroup instance, but 20 | /// the actual components the group cares about) it will return the existing group, if one does not exist 21 | /// it is created. 22 | /// 23 | /// The group to match entities on 24 | /// The collection names to use (defaults to null) 25 | /// An IObservableGroup monitoring the group passed in 26 | IObservableGroup GetObservableGroup(IGroup group, params int[] collectionIds); 27 | } 28 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/Accessor/ComponentAccessor.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using EcsRx.Extensions; 3 | 4 | namespace EcsRx.Components.Accessor 5 | { 6 | public class ComponentAccessor : IComponentAccessor 7 | { 8 | public int ComponentTypeId { get; } 9 | 10 | public ComponentAccessor(int componentTypeTypeId) 11 | { ComponentTypeId = componentTypeTypeId; } 12 | 13 | public bool Has(IEntity entity) => entity.HasComponent(ComponentTypeId); 14 | public T Get(IEntity entity) => (T)entity.GetComponent(ComponentTypeId); 15 | public void Remove(IEntity entity) => entity.RemoveComponents(ComponentTypeId); 16 | 17 | public bool TryGet(IEntity entity, out T component) 18 | { 19 | if (Has(entity)) 20 | { 21 | component = Get(entity); 22 | return true; 23 | } 24 | 25 | component = default; 26 | return false; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/Accessor/IComponentAccessor.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | 3 | namespace EcsRx.Components.Accessor 4 | { 5 | /// 6 | /// Represents an optimised way to interact with a component type on an entity 7 | /// 8 | /// The type of the component 9 | /// 10 | /// In most cases you can just use the provided extension methods on IEntity, however for 11 | /// optimisations purposes this provides you a streamlined way to caching the component 12 | /// type id and relaying calls through to the underlying entity. 13 | /// 14 | public interface IComponentAccessor 15 | { 16 | int ComponentTypeId { get; } 17 | bool Has(IEntity entity); 18 | T Get(IEntity entity); 19 | bool TryGet(IEntity entity, out T component); 20 | void Remove(IEntity entity); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/Database/IComponentDatabase.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Collections; 2 | 3 | namespace EcsRx.Components.Database 4 | { 5 | public interface IComponentDatabase 6 | { 7 | T Get(int componentTypeId, int allocationIndex) where T : IComponent; 8 | ref T GetRef(int componentTypeId, int allocationIndex) where T : IComponent; 9 | T[] GetComponents(int componentTypeId) where T : IComponent; 10 | void Set(int componentTypeId, int allocationIndex, T component) where T : IComponent; 11 | void Remove(int componentTypeId, int allocationIndex); 12 | int Allocate(int componentTypeId); 13 | 14 | void PreAllocateComponents(int componentTypeId, int allocationSize); 15 | IComponentPool GetPoolFor(int componentTypeId) where T : IComponent; 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/IComponent.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Components 2 | { 3 | /// 4 | /// A container for isolated contextual data on an entity, should never contain logic. 5 | /// 6 | /// 7 | /// Components should contain pure data which is passed around to different systems. 8 | /// If you also need to dispose on data inside your component i.e ReactiveProperty vars 9 | /// then just implement IDisposable as well and they will be auto disposed when the entity 10 | /// disposes 11 | /// 12 | public interface IComponent 13 | { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/EcsRx/Components/Lookups/DefaultComponentTypeAssigner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace EcsRx.Components.Lookups 6 | { 7 | public class DefaultComponentTypeAssigner : IComponentTypeAssigner 8 | { 9 | public IEnumerable GetAllComponentTypes() 10 | { 11 | var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 12 | var componentType = typeof(IComponent); 13 | 14 | return assemblies 15 | .SelectMany(s => s.GetTypes()) 16 | .Where(p => componentType.IsAssignableFrom(p) && !p.IsInterface && !p.IsAbstract); 17 | } 18 | 19 | public IReadOnlyDictionary GenerateComponentLookups() 20 | { 21 | var lookupId = 0; 22 | return GetAllComponentTypes()?.ToDictionary(x => x, _ => lookupId++); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/Lookups/IComponentTypeAssigner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace EcsRx.Components.Lookups 5 | { 6 | /// 7 | /// The Component Type Assigner interface is used to generate the internal lookup mappings 8 | /// for component types to ids. 9 | /// 10 | /// 11 | /// The default implementation provided in this framework will use reflection to find all 12 | /// IComponent implementations within the AppDomain and then register them arbitrary values 13 | /// so this may not be consistent between runs. 14 | /// 15 | public interface IComponentTypeAssigner 16 | { 17 | IReadOnlyDictionary GenerateComponentLookups(); 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/Lookups/IComponentTypeLookup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace EcsRx.Components.Lookups 5 | { 6 | /// 7 | /// The Component Type Lookup interface is responsible for looking up 8 | /// component ids for the types as well as vice versa. 9 | /// 10 | public interface IComponentTypeLookup 11 | { 12 | int[] AllComponentTypeIds { get; } 13 | IReadOnlyDictionary GetComponentTypeMappings(); 14 | int GetComponentTypeId(Type type); 15 | Type GetComponentType(int typeId); 16 | bool IsComponentStruct(int componentTypeId); 17 | bool IsComponentDisposable(int componentTypeId); 18 | } 19 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/Lookups/IStructDefaulter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EcsRx.Components.Lookups 4 | { 5 | public interface IStructDefaulter 6 | { 7 | ValueType GetDefault(int index); 8 | bool IsDefault(T value, int index); 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx/Components/Lookups/StructDefaulter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace EcsRx.Components.Lookups 5 | { 6 | public class StructDefaulter : IStructDefaulter 7 | { 8 | public ValueType[] DefaultValueTypeLookups { get; } 9 | 10 | public ValueType GetDefault(int index) => DefaultValueTypeLookups[index]; 11 | public bool IsDefault(T value, int index) => value.Equals(GetDefault(index)); 12 | 13 | public ValueType GenerateDefault(Type type) 14 | { 15 | var defaultObject = Activator.CreateInstance(type); 16 | var fields = type.GetFields(BindingFlags.Public); 17 | 18 | foreach (var field in fields) 19 | { 20 | if (field.IsStatic) { continue; } 21 | 22 | if(field.FieldType.IsPrimitive) 23 | { field.SetValue(defaultObject, byte.MinValue+1); } 24 | } 25 | 26 | return (ValueType)defaultObject; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/EcsRx/Computeds/Groups/IComputedGroup.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Groups.Observable; 2 | 3 | namespace EcsRx.Computeds.Groups 4 | { 5 | public interface IComputedGroup : IObservableGroup 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/EcsRx/EcsRx.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 0.0.0 4 | netstandard2.1 5 | EcsRx 6 | Grofit (LP) 7 | https://github.com/ecsrx/ecsrx/blob/master/LICENSE 8 | https://github.com/ecsrx/ecsrx 9 | A reactive take on the ECS pattern for .net game developers 10 | ecs rx reactive patterns ioc game-development xna monogame unity 11 | 8 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/EcsRx/Entities/DefaultEntityFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SystemsRx.Pools; 3 | using EcsRx.Components.Database; 4 | using EcsRx.Components.Lookups; 5 | 6 | namespace EcsRx.Entities 7 | { 8 | public class DefaultEntityFactory : IEntityFactory 9 | { 10 | public IIdPool IdPool { get; } 11 | public IComponentDatabase ComponentDatabase { get; } 12 | public IComponentTypeLookup ComponentTypeLookup { get; } 13 | 14 | public DefaultEntityFactory(IIdPool idPool, IComponentDatabase componentDatabase, IComponentTypeLookup componentTypeLookup) 15 | { 16 | IdPool = idPool; 17 | ComponentDatabase = componentDatabase; 18 | ComponentTypeLookup = componentTypeLookup; 19 | } 20 | 21 | public int GetId(int? id = null) 22 | { 23 | if(!id.HasValue) 24 | { return IdPool.AllocateInstance(); } 25 | 26 | IdPool.AllocateSpecificId(id.Value); 27 | return id.Value; 28 | } 29 | 30 | public IEntity Create(int? id = null) 31 | { 32 | if(id.HasValue && id.Value == 0) 33 | { throw new ArgumentException("id must be null or > 0"); } 34 | 35 | var usedId = GetId(id); 36 | return new Entity(usedId, ComponentDatabase, ComponentTypeLookup); 37 | } 38 | 39 | public void Destroy(int entityId) 40 | { IdPool.ReleaseInstance(entityId); } 41 | } 42 | } -------------------------------------------------------------------------------- /src/EcsRx/Entities/IEntityFactory.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Factories; 2 | 3 | namespace EcsRx.Entities 4 | { 5 | /// 6 | /// Creates entities with given Ids 7 | /// 8 | /// 9 | /// This is meant to be implemented if you want to create your own IEntity 10 | /// implementations as this acts as an abstraction layer over how the entities are created 11 | /// 12 | public interface IEntityFactory : IFactory 13 | { 14 | void Destroy(int entityId); 15 | } 16 | } -------------------------------------------------------------------------------- /src/EcsRx/Exceptions/InvalidEntityException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EcsRx.Exceptions 4 | { 5 | public class InvalidEntityException : Exception 6 | { 7 | public InvalidEntityException(string message) : base(message) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx/Extensions/IBlueprintExtensions.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Blueprints; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Extensions 5 | { 6 | public static class IBlueprintExtensions 7 | { 8 | public static void ApplyToAll(this IBlueprint blueprint, params IEntity[] entities) 9 | { 10 | for (var i = 0; i < entities.Length; i++) 11 | { blueprint.Apply(entities[i]); } 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/EcsRx/Extensions/IComponentAccessorExtensions.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | using EcsRx.Components.Accessor; 3 | using EcsRx.Entities; 4 | 5 | namespace EcsRx.Extensions 6 | { 7 | public static class IComponentAccessorExtensions 8 | { 9 | public static ref T Add(this IComponentAccessor accessor, IEntity entity) 10 | where T : IComponent, new() => ref entity.AddComponent(accessor.ComponentTypeId); 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx/Extensions/IComponentDatabaseExtensions.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Components; 2 | using EcsRx.Components.Database; 3 | 4 | namespace EcsRx.Extensions 5 | { 6 | public static class IComponentDatabaseExtensions 7 | { 8 | public static IComponent Get(this IComponentDatabase componentDatabase, int allocationIndex, int componentTypeId) 9 | { return componentDatabase.Get(componentTypeId, allocationIndex); } 10 | } 11 | } -------------------------------------------------------------------------------- /src/EcsRx/Extensions/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using EcsRx.Attributes; 5 | using EcsRx.Components; 6 | using EcsRx.Entities; 7 | using EcsRx.Groups; 8 | using EcsRx.Systems; 9 | 10 | namespace EcsRx.Extensions 11 | { 12 | public static class IEnumerableExtensions 13 | { 14 | public static IEnumerable MatchingGroup(this IEnumerable entities, IGroup group) 15 | { return entities.Where(group.Matches); } 16 | 17 | public static IEnumerable MatchingGroup(this IEnumerable entities, LookupGroup group) 18 | { return entities.Where(x => group.Matches(x)); } 19 | 20 | public static IEnumerable GetApplicableSystems(this IEnumerable systems, IEntity entity) 21 | { return systems.Where(x => entity.MatchesGroup(x.Group)); } 22 | 23 | public static IEnumerable GetApplicableSystems(this IEnumerable systems, IEnumerable components) 24 | { 25 | var componentTypes = components.Select(x => x.GetType()); 26 | return systems.Where(x => x.Group.RequiredComponents.All(y => componentTypes.Contains(y))); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/EcsRx/Extensions/IObservableGroupExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EcsRx.Entities; 3 | using EcsRx.Groups.Observable; 4 | 5 | namespace EcsRx.Extensions 6 | { 7 | public static class IObservableGroupExtensions 8 | { 9 | public static IEnumerable Query(this IObservableGroup observableGroupAccesssor, IObservableGroupQuery query) 10 | { return query.Execute(observableGroupAccesssor); } 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx/Extensions/IObservableGroupTrackerExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Extensions 2 | { 3 | public static class IObservableGroupTrackerExtensions 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /src/EcsRx/Extensions/ISystemExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using EcsRx.Attributes; 4 | using EcsRx.Groups; 5 | using EcsRx.Systems; 6 | using SystemsRx.Extensions; 7 | using SystemsRx.Systems; 8 | 9 | namespace EcsRx.Extensions 10 | { 11 | public static class ISystemExtensions 12 | { 13 | public static IGroup GroupFor(this IGroupSystem groupSystem, params Type[] requiredTypes) 14 | { return new Group(requiredTypes); } 15 | 16 | public static int[] GetGroupAffinities(this IGroupSystem system) 17 | { 18 | if (system is null) 19 | { throw new ArgumentNullException(nameof(system)); } 20 | 21 | var affinity = system.GetType().GetCustomAttribute(typeof(CollectionAffinityAttribute), true); 22 | 23 | return ((CollectionAffinityAttribute) affinity)?.CollectionIds; 24 | } 25 | 26 | public static int[] GetGroupAffinities(this ISystem system, MemberInfo memberInfo) 27 | { 28 | if (memberInfo is null) 29 | { throw new ArgumentNullException(nameof(memberInfo)); } 30 | 31 | var collectionAffinityAttribute = (CollectionAffinityAttribute)memberInfo.GetCustomAttribute(typeof(CollectionAffinityAttribute), true); 32 | return collectionAffinityAttribute?.CollectionIds; 33 | } 34 | 35 | public static bool IsSystemReactive(this ISystem system) 36 | { return system is IReactToEntitySystem || system is IReactToGroupSystem || system.IsReactiveDataSystem(); } 37 | 38 | public static bool IsReactiveDataSystem(this ISystem system) 39 | { return system.MatchesSystemTypeWithGeneric(typeof(IReactToDataSystem<>)); } 40 | } 41 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/EmptyGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EcsRx.Groups 4 | { 5 | public class EmptyGroup : IGroup 6 | { 7 | public Type[] RequiredComponents { get; } = Array.Empty(); 8 | public Type[] ExcludedComponents { get; } = Array.Empty(); 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Group.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace EcsRx.Groups 6 | { 7 | public class Group : IGroup 8 | { 9 | public static readonly IGroup Empty = new EmptyGroup(); 10 | 11 | public Type[] RequiredComponents { get; } 12 | public Type[] ExcludedComponents { get; } 13 | 14 | /// 15 | /// Hint: maybe consider using Group.Empty for better performance, unless you plan on changing the group afterwards. 16 | /// 17 | public Group() 18 | { 19 | RequiredComponents = Array.Empty(); 20 | ExcludedComponents = Array.Empty(); 21 | } 22 | 23 | public Group(params Type[] requiredComponents) 24 | { 25 | RequiredComponents = requiredComponents?.ToArray() ?? Array.Empty(); 26 | ExcludedComponents = Array.Empty(); 27 | } 28 | 29 | public Group(IEnumerable requiredComponents, IEnumerable excludedComponents) 30 | { 31 | RequiredComponents = requiredComponents?.ToArray() ?? Array.Empty(); 32 | ExcludedComponents = excludedComponents?.ToArray() ?? Array.Empty(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/GroupWithPredicate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EcsRx.Entities; 4 | 5 | namespace EcsRx.Groups 6 | { 7 | public class GroupWithPredicate : Group, IHasPredicate 8 | { 9 | public Predicate EntityPredicate { get; } 10 | 11 | public GroupWithPredicate(Predicate entityPredicate, params Type[] requiredComponents): this(entityPredicate, requiredComponents, Array.Empty()){} 12 | 13 | public GroupWithPredicate(Predicate entityPredicate, IEnumerable requiredComponents, IEnumerable excludedComponents) : base(requiredComponents, excludedComponents) 14 | { 15 | EntityPredicate = entityPredicate; 16 | } 17 | 18 | public bool CanProcessEntity (IEntity entity) 19 | { return EntityPredicate == null || EntityPredicate(entity); } 20 | } 21 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/IGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EcsRx.Groups 4 | { 5 | public interface IGroup 6 | { 7 | Type[] RequiredComponents { get; } 8 | Type[] ExcludedComponents { get; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/IHasPredicate.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | 3 | namespace EcsRx.Groups 4 | { 5 | public interface IHasPredicate 6 | { 7 | bool CanProcessEntity(IEntity entity); 8 | } 9 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/LookupGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Linq; 4 | 5 | namespace EcsRx.Groups 6 | { 7 | public readonly struct LookupGroup 8 | { 9 | public int[] RequiredComponents { get; } 10 | public int[] ExcludedComponents { get; } 11 | 12 | public LookupGroup(int[] requiredComponents, int[] excludedComponents) 13 | { 14 | RequiredComponents = requiredComponents; 15 | ExcludedComponents = excludedComponents; 16 | } 17 | 18 | public bool Equals(LookupGroup other) 19 | { 20 | return StructuralComparisons.StructuralEqualityComparer.Equals(RequiredComponents, other.RequiredComponents) && 21 | StructuralComparisons.StructuralEqualityComparer.Equals(ExcludedComponents, other.ExcludedComponents); 22 | } 23 | 24 | public override bool Equals(object obj) 25 | { 26 | return obj is LookupGroup other && Equals(other); 27 | } 28 | 29 | public override int GetHashCode() 30 | { 31 | unchecked 32 | { 33 | return ((RequiredComponents != null ? StructuralComparisons.StructuralEqualityComparer.GetHashCode(RequiredComponents) : 0) * 397) ^ (ExcludedComponents != null ? StructuralComparisons.StructuralEqualityComparer.GetHashCode(ExcludedComponents) : 0); 34 | } 35 | } 36 | 37 | public static bool operator ==(LookupGroup left, LookupGroup right) 38 | { 39 | return left.Equals(right); 40 | } 41 | 42 | public static bool operator !=(LookupGroup left, LookupGroup right) 43 | { 44 | return !left.Equals(right); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/DefaultObservableObservableGroupFactory.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Groups.Observable.Tracking; 2 | 3 | namespace EcsRx.Groups.Observable 4 | { 5 | public class DefaultObservableObservableGroupFactory : IObservableGroupFactory 6 | { 7 | private IGroupTrackerFactory GroupTrackerFactory { get; } 8 | 9 | public DefaultObservableObservableGroupFactory(IGroupTrackerFactory groupTrackerFactory) 10 | { 11 | GroupTrackerFactory = groupTrackerFactory; 12 | } 13 | 14 | public IObservableGroup Create(ObservableGroupConfiguration arg) 15 | { 16 | var tracker = GroupTrackerFactory.TrackGroup(arg.ObservableGroupToken.LookupGroup, arg.InitialEntities, arg.NotifyingCollections); 17 | return new ObservableGroup(arg.ObservableGroupToken, arg.InitialEntities, tracker); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/IObservableGroupFactory.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Factories; 2 | 3 | namespace EcsRx.Groups.Observable 4 | { 5 | public interface IObservableGroupFactory : IFactory {} 6 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/IObservableGroupQuery.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Groups.Observable 5 | { 6 | public interface IObservableGroupQuery 7 | { 8 | IEnumerable Execute(IObservableGroup observableGroup); 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/ObservableGroupConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EcsRx.Collections.Entity; 3 | using EcsRx.Entities; 4 | 5 | namespace EcsRx.Groups.Observable 6 | { 7 | public class ObservableGroupConfiguration 8 | { 9 | public ObservableGroupToken ObservableGroupToken { get; set; } 10 | public IEnumerable NotifyingCollections { get; set; } 11 | public IEnumerable InitialEntities { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/ObservableGroupToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EcsRx.Groups.Observable 4 | { 5 | public struct ObservableGroupToken : IEquatable 6 | { 7 | public LookupGroup LookupGroup { get; } 8 | public int[] CollectionIds { get; } 9 | 10 | public ObservableGroupToken(int[] withComponents, int[] withoutComponents, params int[] collectionIds) 11 | { 12 | LookupGroup = new LookupGroup(withComponents, withoutComponents); 13 | CollectionIds = collectionIds; 14 | } 15 | 16 | public ObservableGroupToken(LookupGroup lookupGroup, params int[] collectionIds) 17 | { 18 | LookupGroup = lookupGroup; 19 | CollectionIds = collectionIds; 20 | } 21 | 22 | public bool Equals(ObservableGroupToken other) 23 | { 24 | return LookupGroup.Equals(other.LookupGroup) && CollectionIds == other.CollectionIds; 25 | } 26 | 27 | public override int GetHashCode() 28 | { 29 | var lookupHash = LookupGroup.GetHashCode(); 30 | var poolHash = CollectionIds?.GetHashCode() ?? 0; 31 | return lookupHash ^ poolHash; 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/Events/EntityGroupStateChanged.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Groups.Observable.Tracking.Types; 4 | 5 | namespace EcsRx.Groups.Observable.Tracking.Events 6 | { 7 | public readonly struct EntityGroupStateChanged : IEquatable 8 | { 9 | public readonly IEntity Entity; 10 | public readonly GroupActionType GroupActionType; 11 | 12 | public EntityGroupStateChanged(IEntity entity, GroupActionType groupActionType) 13 | { 14 | Entity = entity; 15 | GroupActionType = groupActionType; 16 | } 17 | 18 | public bool Equals(EntityGroupStateChanged other) 19 | { 20 | return Equals(Entity, other.Entity) && GroupActionType == other.GroupActionType; 21 | } 22 | 23 | public override bool Equals(object obj) 24 | { 25 | return obj is EntityGroupStateChanged other && Equals(other); 26 | } 27 | 28 | public override int GetHashCode() 29 | { 30 | unchecked 31 | { 32 | return ((Entity != null ? Entity.GetHashCode() : 0) * 397) ^ (int)GroupActionType; 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/IGroupTrackerFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EcsRx.Collections.Entity; 3 | using EcsRx.Entities; 4 | using EcsRx.Groups.Observable.Tracking.Trackers; 5 | 6 | namespace EcsRx.Groups.Observable.Tracking 7 | { 8 | public interface IGroupTrackerFactory 9 | { 10 | ICollectionObservableGroupTracker TrackGroup(IGroup group, IEnumerable initialEntities, IEnumerable notifyingEntityComponentChanges); 11 | ICollectionObservableGroupTracker TrackGroup(LookupGroup group, IEnumerable initialEntities, IEnumerable notifyingEntityComponentChanges); 12 | IBatchObservableGroupTracker TrackGroup(IGroup group); 13 | IBatchObservableGroupTracker TrackGroup(LookupGroup group); 14 | IIndividualObservableGroupTracker TrackGroup(IGroup group, IEntity entity); 15 | IIndividualObservableGroupTracker TrackGroup(LookupGroup group, IEntity entity); 16 | } 17 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/Trackers/IBatchObservableGroupTracker.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | 3 | namespace EcsRx.Groups.Observable.Tracking.Trackers 4 | { 5 | public interface IBatchObservableGroupTracker : ICollectionObservableGroupTracker 6 | { 7 | bool StartTrackingEntity(IEntity entity); 8 | void StopTrackingEntity(IEntity entity); 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/Trackers/ICollectionObservableGroupTracker.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Groups.Observable.Tracking.Trackers 2 | { 3 | public interface ICollectionObservableGroupTracker : IObservableGroupTracker 4 | { 5 | bool IsMatching(int entityId); 6 | } 7 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/Trackers/IIndividualObservableGroupTracker.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Groups.Observable.Tracking.Trackers 2 | { 3 | public interface IIndividualObservableGroupTracker : IObservableGroupTracker 4 | { 5 | bool IsMatching(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/Trackers/IObservableGroupTracker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Groups.Observable.Tracking.Events; 3 | 4 | namespace EcsRx.Groups.Observable.Tracking.Trackers 5 | { 6 | public interface IObservableGroupTracker : IDisposable 7 | { 8 | IObservable GroupMatchingChanged { get; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/Types/GroupActionType.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Groups.Observable.Tracking.Types 2 | { 3 | public enum GroupActionType : byte 4 | { 5 | Unknown = 0, 6 | JoinedGroup = 1, 7 | LeavingGroup = 2, 8 | LeftGroup = 3 9 | } 10 | } -------------------------------------------------------------------------------- /src/EcsRx/Groups/Observable/Tracking/Types/GroupMatchingType.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Groups.Observable.Tracking.Types 2 | { 3 | public enum GroupMatchingType : byte 4 | { 5 | NoMatchesFound = 0, 6 | 7 | MatchesNoExcludes = 1, 8 | MatchesWithExcludes = 2, 9 | NoMatchesWithExcludes = 3, 10 | NoMatchesNoExcludes = 4 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx/Lookups/CollectionLookup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using EcsRx.Collections; 3 | using EcsRx.Collections.Entity; 4 | 5 | namespace EcsRx.Lookups 6 | { 7 | public class CollectionLookup : KeyedCollection 8 | { 9 | protected override int GetKeyForItem(IEntityCollection item) => item.Id; 10 | 11 | public IEntityCollection GetByIndex(int index) => Items[index]; 12 | } 13 | } -------------------------------------------------------------------------------- /src/EcsRx/Lookups/EntityLookup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Lookups 5 | { 6 | public class EntityLookup : KeyedCollection 7 | { 8 | protected override int GetKeyForItem(IEntity item) => item.Id; 9 | 10 | public IEntity GetByIndex(int index) => Items[index]; 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx/Lookups/ObservableGroupLookup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using EcsRx.Groups.Observable; 3 | 4 | namespace EcsRx.Lookups 5 | { 6 | public class ObservableGroupLookup : KeyedCollection 7 | { 8 | protected override ObservableGroupToken GetKeyForItem(IObservableGroup item) => item.Token; 9 | 10 | public IObservableGroup GetByIndex(int index) => Items[index]; 11 | } 12 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/IBasicEntitySystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | using SystemsRx.Scheduling; 3 | 4 | namespace EcsRx.Systems 5 | { 6 | /// 7 | /// A system which processes every entity every update 8 | /// 9 | /// 10 | /// This relies upon the underlying IObservableScheduler implementation and 11 | /// is by default aiming for 60 updates per second. 12 | /// 13 | public interface IBasicEntitySystem : IGroupSystem 14 | { 15 | /// 16 | /// The processor to handle the entity 17 | /// 18 | /// The entity to process 19 | /// The elapsedTime since last update 20 | void Process(IEntity entity, ElapsedTime elapsedTime); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/IGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using SystemsRx.Systems; 2 | using EcsRx.Groups; 3 | using EcsRx.Groups.Observable; 4 | 5 | namespace EcsRx.Systems 6 | { 7 | /// 8 | /// The base interface for all systems, this is rarely used directly 9 | /// 10 | public interface IGroupSystem : ISystem 11 | { 12 | /// 13 | /// The group to target with this system 14 | /// 15 | IGroup Group { get; } 16 | } 17 | 18 | public interface IObservableGroupSystem : IGroupSystem 19 | { 20 | IObservableGroup ObservableGroup { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/IReactToDataSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Systems 5 | { 6 | /// 7 | /// React to data systems are a more advanced version of React To Entity systems, 8 | /// they allow you to not only react to entity changes but also pass back custom 9 | /// payloads to the executor, use this if you need to react with custom data 10 | /// 11 | /// The type of payload to react with 12 | public interface IReactToDataSystem : IGroupSystem 13 | { 14 | /// 15 | /// Returns and observable indicating both when the system should execute for a given entity 16 | /// as well as what the data should be to be passed to the executor 17 | /// 18 | /// The entity to react to 19 | /// Observable containing data 20 | IObservable ReactToData(IEntity entity); 21 | 22 | /// 23 | /// The executor which is passed both the entity and the data from the reaction 24 | /// 25 | /// The entity to use 26 | /// The data from the reaction 27 | void Process(IEntity entity, T reactionData); 28 | } 29 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/IReactToEntitySystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | 4 | namespace EcsRx.Systems 5 | { 6 | /// 7 | /// React To Entity systems react as and when the entity needs to be processed, 8 | /// this means rather than batching all updates at once, it instead allows you 9 | /// to react on each entity individually, i.e when the entity has less than 50% 10 | /// hp. 11 | /// 12 | /// 13 | /// If you do not need to react to each entity individually it is recommended you 14 | /// use a React To LookupGroup system as they have less overhead as there is only one 15 | /// subscription required rather than 1 per entity. 16 | /// 17 | public interface IReactToEntitySystem : IGroupSystem 18 | { 19 | /// 20 | /// Returns and observable indicating when the system should execute for a given entity 21 | /// 22 | /// The entity to react to 23 | /// Observable indicating when the system should execute 24 | IObservable ReactToEntity(IEntity entity); 25 | 26 | /// 27 | /// The processor to handle the entity reaction 28 | /// 29 | /// The entity to use 30 | void Process(IEntity entity); 31 | } 32 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/IReactToGroupExSystem.cs: -------------------------------------------------------------------------------- 1 | namespace EcsRx.Systems 2 | { 3 | public interface IReactToGroupExSystem : IReactToGroupSystem 4 | { 5 | /// 6 | /// Triggered before the group is processed 7 | /// 8 | void BeforeProcessing(); 9 | 10 | /// 11 | /// Triggered after the group is processed 12 | /// 13 | void AfterProcessing(); 14 | } 15 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/IReactToGroupSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EcsRx.Entities; 3 | using EcsRx.Groups.Observable; 4 | 5 | namespace EcsRx.Systems 6 | { 7 | /// 8 | /// React To LookupGroup systems are the more common ECS style system, 9 | /// as they batch handle all applicable entities at once. This means 10 | /// you do not react to individual entities and instead react at the 11 | /// group level, be it every frame or time period. 12 | /// 13 | /// 14 | /// This is the most common use case system, as it aligns with common 15 | /// ECS paradigms, i.e a system which triggers every update and runs 16 | /// on all applicable entities. If you need more control over individual 17 | /// entity reactions etc then look at ReactToEntity/Data systems. 18 | /// 19 | public interface IReactToGroupSystem : IGroupSystem 20 | { 21 | /// 22 | /// Dictates when the group should be processed 23 | /// 24 | /// The observable group to process 25 | /// The observable chain containing the group 26 | /// 27 | /// In most use cases you probably want to run this every update/interval 28 | /// 29 | IObservable ReactToGroup(IObservableGroup observableGroup); 30 | 31 | /// 32 | /// The processor for the entity 33 | /// 34 | /// The entity to process 35 | void Process(IEntity entity); 36 | } 37 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/ISetupSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | 3 | namespace EcsRx.Systems 4 | { 5 | /// 6 | /// Setup systems are run ONCE when an entity joins a given group, 7 | /// there is also some additional logic around handling predicates so if 8 | /// an entity matches a group BUT it has a predicate that is not met, the entity 9 | /// will be monitored and when the entity matches the group and the predicate 10 | /// passes it will then run the setup. 11 | /// 12 | /// 13 | /// If the entity leaves the group and re-joins it will re-trigger the setup 14 | /// method on there so keep this in mind, and just because components match 15 | /// if there is a predicate that doesn't match then it wont be run until it 16 | /// does match. 17 | /// 18 | public interface ISetupSystem : IGroupSystem 19 | { 20 | /// 21 | /// The logic run when the entity needs setting up 22 | /// 23 | /// The entity to setup 24 | void Setup(IEntity entity); 25 | } 26 | } -------------------------------------------------------------------------------- /src/EcsRx/Systems/ITeardownSystem.cs: -------------------------------------------------------------------------------- 1 | using EcsRx.Entities; 2 | 3 | namespace EcsRx.Systems 4 | { 5 | /// 6 | /// Teardown systems are run ONCE when an entity is ABOUT TO LEAVE a given group, 7 | /// this means the entity will still contain all components etc as this system 8 | /// is triggered just before components/entities are removed. 9 | /// 10 | /// 11 | /// If the entity joins the group and leaves again it will re-trigger the teardown 12 | /// method on there so keep this in mind. You can also combine ISetupSystem and 13 | /// ITeardownSystem on the same implementation which is often useful. 14 | /// 15 | public interface ITeardownSystem : IGroupSystem 16 | { 17 | /// 18 | /// The teardown method to be run when the entity is leaving the group 19 | /// 20 | /// The entity to teardown 21 | void Teardown(IEntity entity); 22 | } 23 | } --------------------------------------------------------------------------------